add lockState and syncState to getFrontendInfo call
[enigma2.git] / lib / service / servicedvb.cpp
1 #include <lib/base/eerror.h>
2 #include <lib/base/object.h>
3 #include <string>
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>
8
9 #include <lib/dvb/dvb.h>
10 #include <lib/dvb/db.h>
11 #include <lib/dvb/decoder.h>
12
13 #include <lib/service/servicedvbrecord.h>
14 #include <lib/service/event.h>
15 #include <lib/dvb/metaparser.h>
16 #include <lib/dvb/tstools.h>
17 #include <lib/python/python.h>
18
19 #include <sys/vfs.h>
20
21 #include <byteswap.h>
22 #include <netinet/in.h>
23
24 #include <dvbsi++/event_information_section.h>
25
26 #ifndef BYTE_ORDER
27 #error no byte order defined!
28 #endif
29
30 #define TSPATH "/media/hdd"
31
32 class eStaticServiceDVBInformation: public iStaticServiceInformation
33 {
34         DECLARE_REF(eStaticServiceDVBInformation);
35 public:
36         RESULT getName(const eServiceReference &ref, std::string &name);
37         int getLength(const eServiceReference &ref);
38 };
39
40 DEFINE_REF(eStaticServiceDVBInformation);
41
42 RESULT eStaticServiceDVBInformation::getName(const eServiceReference &ref, std::string &name)
43 {
44         eServiceReferenceDVB &service = (eServiceReferenceDVB&)ref;
45         if ( !ref.name.empty() )
46         {
47                 if (service.getParentTransportStreamID().get()) // linkage subservice
48                 {
49                         ePtr<iServiceHandler> service_center;
50                         if (!eServiceCenter::getInstance(service_center))
51                         {
52                                 eServiceReferenceDVB parent = service;
53                                 parent.setTransportStreamID( service.getParentTransportStreamID() );
54                                 parent.setServiceID( service.getParentServiceID() );
55                                 parent.setParentTransportStreamID(eTransportStreamID(0));
56                                 parent.setParentServiceID(eServiceID(0));
57                                 parent.name="";
58                                 ePtr<iStaticServiceInformation> service_info;
59                                 if (!service_center->info(parent, service_info))
60                                 {
61                                         if (!service_info->getName(parent, name))
62                                         {
63                                                 // just show short name
64                                                 unsigned int pos = name.find("\xc2\x86");
65                                                 if ( pos != std::string::npos )
66                                                         name.erase(0, pos+2);
67                                                 pos = name.find("\xc2\x87");
68                                                 if ( pos != std::string::npos )
69                                                         name.erase(pos);
70                                                 name+=" - ";
71                                         }
72                                 }
73                         }
74                 }
75                 else
76                         name="";
77                 name += ref.name;
78                 return 0;
79         }
80         else
81                 return -1;
82 }
83
84 int eStaticServiceDVBInformation::getLength(const eServiceReference &ref)
85 {
86         return -1;
87 }
88
89 class eStaticServiceDVBBouquetInformation: public iStaticServiceInformation
90 {
91         DECLARE_REF(eStaticServiceDVBBouquetInformation);
92 public:
93         RESULT getName(const eServiceReference &ref, std::string &name);
94         int getLength(const eServiceReference &ref);
95 };
96
97 DEFINE_REF(eStaticServiceDVBBouquetInformation);
98
99 RESULT eStaticServiceDVBBouquetInformation::getName(const eServiceReference &ref, std::string &name)
100 {
101         ePtr<iDVBChannelList> db;
102         ePtr<eDVBResourceManager> res;
103
104         int err;
105         if ((err = eDVBResourceManager::getInstance(res)) != 0)
106         {
107                 eDebug("eStaticServiceDVBBouquetInformation::getName failed.. no resource manager!");
108                 return err;
109         }
110         if ((err = res->getChannelList(db)) != 0)
111         {
112                 eDebug("eStaticServiceDVBBouquetInformation::getName failed.. no channel list!");
113                 return err;
114         }
115
116         eBouquet *bouquet=0;
117         if ((err = db->getBouquet(ref, bouquet)) != 0)
118         {
119                 eDebug("eStaticServiceDVBBouquetInformation::getName failed.. getBouquet failed!");
120                 return -1;
121         }
122
123         if ( bouquet && bouquet->m_bouquet_name.length() )
124         {
125                 name = bouquet->m_bouquet_name;
126                 return 0;
127         }
128         else
129                 return -1;
130 }
131
132 int eStaticServiceDVBBouquetInformation::getLength(const eServiceReference &ref)
133 {
134         return -1;
135 }
136
137 class eStaticServiceDVBPVRInformation: public iStaticServiceInformation
138 {
139         DECLARE_REF(eStaticServiceDVBPVRInformation);
140         eServiceReference m_ref;
141         eDVBMetaParser m_parser;
142 public:
143         eStaticServiceDVBPVRInformation(const eServiceReference &ref);
144         RESULT getName(const eServiceReference &ref, std::string &name);
145         int getLength(const eServiceReference &ref);
146         
147         int getInfo(const eServiceReference &ref, int w);
148         std::string getInfoString(const eServiceReference &ref,int w);
149 };
150
151 DEFINE_REF(eStaticServiceDVBPVRInformation);
152
153 eStaticServiceDVBPVRInformation::eStaticServiceDVBPVRInformation(const eServiceReference &ref)
154 {
155         m_ref = ref;
156         m_parser.parseFile(ref.path);
157 }
158
159 RESULT eStaticServiceDVBPVRInformation::getName(const eServiceReference &ref, std::string &name)
160 {
161         ASSERT(ref == m_ref);
162         name = m_parser.m_name.size() ? m_parser.m_name : ref.path;
163         return 0;
164 }
165
166 int eStaticServiceDVBPVRInformation::getLength(const eServiceReference &ref)
167 {
168         ASSERT(ref == m_ref);
169         
170         eDVBTSTools tstools;
171         
172         if (tstools.openFile(ref.path.c_str()))
173                 return 0;
174
175         pts_t len;
176         if (tstools.calcLen(len))
177                 return 0;
178
179         return len / 90000;
180 }
181
182 int eStaticServiceDVBPVRInformation::getInfo(const eServiceReference &ref, int w)
183 {
184         switch (w)
185         {
186         case iServiceInformation::sDescription:
187                 return iServiceInformation::resIsString;
188         case iServiceInformation::sTimeCreate:
189                 if (m_parser.m_time_create)
190                         return m_parser.m_time_create;
191                 else
192                         return iServiceInformation::resNA;
193         default:
194                 return iServiceInformation::resNA;
195         }
196 }
197
198 std::string eStaticServiceDVBPVRInformation::getInfoString(const eServiceReference &ref,int w)
199 {
200         switch (w)
201         {
202         case iServiceInformation::sDescription:
203                 return m_parser.m_description;
204         default:
205                 return "";
206         }
207 }
208
209 class eDVBPVRServiceOfflineOperations: public iServiceOfflineOperations
210 {
211         DECLARE_REF(eDVBPVRServiceOfflineOperations);
212         eServiceReferenceDVB m_ref;
213 public:
214         eDVBPVRServiceOfflineOperations(const eServiceReference &ref);
215         
216         RESULT deleteFromDisk(int simulate);
217         RESULT getListOfFilenames(std::list<std::string> &);
218 };
219
220 DEFINE_REF(eDVBPVRServiceOfflineOperations);
221
222 eDVBPVRServiceOfflineOperations::eDVBPVRServiceOfflineOperations(const eServiceReference &ref): m_ref((const eServiceReferenceDVB&)ref)
223 {
224 }
225
226 RESULT eDVBPVRServiceOfflineOperations::deleteFromDisk(int simulate)
227 {
228         if (simulate)
229                 return 0;
230         else
231         {
232                 std::list<std::string> res;
233                 if (getListOfFilenames(res))
234                         return -1;
235                 
236                                 /* TODO: deferred removing.. */
237                 for (std::list<std::string>::iterator i(res.begin()); i != res.end(); ++i)
238                 {
239                         eDebug("Removing %s...", i->c_str());
240                         ::unlink(i->c_str());
241                 }
242                 
243                 return 0;
244         }
245 }
246
247 RESULT eDVBPVRServiceOfflineOperations::getListOfFilenames(std::list<std::string> &res)
248 {
249         res.clear();
250         res.push_back(m_ref.path);
251         res.push_back(m_ref.path + ".meta");
252         res.push_back(m_ref.path + ".ap");
253         res.push_back(m_ref.path + ".cuts");
254         res.push_back(m_ref.path + ".eit");
255         return 0;
256 }
257
258 DEFINE_REF(eServiceFactoryDVB)
259
260 eServiceFactoryDVB::eServiceFactoryDVB()
261 {
262         ePtr<eServiceCenter> sc;
263         
264         eServiceCenter::getPrivInstance(sc);
265         if (sc)
266                 sc->addServiceFactory(eServiceFactoryDVB::id, this);
267 }
268
269 eServiceFactoryDVB::~eServiceFactoryDVB()
270 {
271         ePtr<eServiceCenter> sc;
272         
273         eServiceCenter::getPrivInstance(sc);
274         if (sc)
275                 sc->removeServiceFactory(eServiceFactoryDVB::id);
276 }
277
278 DEFINE_REF(eDVBServiceList);
279
280 eDVBServiceList::eDVBServiceList(const eServiceReference &parent): m_parent(parent)
281 {
282 }
283
284 eDVBServiceList::~eDVBServiceList()
285 {
286 }
287
288 RESULT eDVBServiceList::startQuery()
289 {
290         ePtr<iDVBChannelList> db;
291         ePtr<eDVBResourceManager> res;
292         
293         int err;
294         if ((err = eDVBResourceManager::getInstance(res)) != 0)
295         {
296                 eDebug("no resource manager");
297                 return err;
298         }
299         if ((err = res->getChannelList(db)) != 0)
300         {
301                 eDebug("no channel list");
302                 return err;
303         }
304         
305         ePtr<eDVBChannelQuery> q;
306         
307         if (!m_parent.path.empty())
308         {
309                 eDVBChannelQuery::compile(q, m_parent.path);
310                 if (!q)
311                 {
312                         eDebug("compile query failed");
313                         return err;
314                 }
315         }
316         
317         if ((err = db->startQuery(m_query, q, m_parent)) != 0)
318         {
319                 eDebug("startQuery failed");
320                 return err;
321         }
322
323         return 0;
324 }
325
326 RESULT eDVBServiceList::getContent(PyObject *list, bool sorted)
327 {
328         eServiceReferenceDVB ref;
329
330         if (!m_query || !list || !PyList_Check(list))
331                 return -1;
332
333         std::list<eServiceReferenceDVB> tmplist;
334
335         while (!m_query->getNextResult(ref))
336                 tmplist.push_back(ref);
337
338         if (sorted)
339                 tmplist.sort(iListableServiceCompare(this));
340
341         for (std::list<eServiceReferenceDVB>::iterator it(tmplist.begin());
342                 it != tmplist.end(); ++it)
343         {
344                 PyObject *refobj = New_eServiceReference(*it);
345                 PyList_Append(list, refobj);
346                 Py_DECREF(refobj);
347         }
348         return 0;
349 }
350
351 RESULT eDVBServiceList::getContent(std::list<eServiceReference> &list, bool sorted)
352 {
353         eServiceReferenceDVB ref;
354         
355         if (!m_query)
356                 return -1;
357         
358         while (!m_query->getNextResult(ref))
359                 list.push_back(ref);
360
361         if (sorted)
362                 list.sort(iListableServiceCompare(this));
363
364         return 0;
365 }
366
367 RESULT eDVBServiceList::getNext(eServiceReference &ref)
368 {
369         if (!m_query)
370                 return -1;
371         
372         return m_query->getNextResult((eServiceReferenceDVB&)ref);
373 }
374
375 int eDVBServiceList::compareLessEqual(const eServiceReference &a, const eServiceReference &b)
376 {
377         return m_query->compareLessEqual((const eServiceReferenceDVB&)a, (const eServiceReferenceDVB&)b);
378 }
379
380 RESULT eDVBServiceList::startEdit(ePtr<iMutableServiceList> &res)
381 {
382         if (m_parent.flags & eServiceReference::flagDirectory) // bouquet
383         {
384                 ePtr<iDVBChannelList> db;
385                 ePtr<eDVBResourceManager> resm;
386
387                 if (eDVBResourceManager::getInstance(resm) || resm->getChannelList(db))
388                         return -1;
389
390                 if (db->getBouquet(m_parent, m_bouquet) != 0)
391                         return -1;
392
393                 res = this;
394                 
395                 return 0;
396         }
397         res = 0;
398         return -1;
399 }
400
401 RESULT eDVBServiceList::addService(eServiceReference &ref)
402 {
403         if (!m_bouquet)
404                 return -1;
405         return m_bouquet->addService(ref);
406 }
407
408 RESULT eDVBServiceList::removeService(eServiceReference &ref)
409 {
410         if (!m_bouquet)
411                 return -1;
412         return m_bouquet->removeService(ref);
413 }
414
415 RESULT eDVBServiceList::moveService(eServiceReference &ref, int pos)
416 {
417         if (!m_bouquet)
418                 return -1;
419         return m_bouquet->moveService(ref, pos);
420 }
421
422 RESULT eDVBServiceList::flushChanges()
423 {
424         if (!m_bouquet)
425                 return -1;
426         return m_bouquet->flushChanges();
427 }
428
429 RESULT eDVBServiceList::setListName(const std::string &name)
430 {
431         if (!m_bouquet)
432                 return -1;
433         return m_bouquet->setListName(name);
434 }
435
436 RESULT eServiceFactoryDVB::play(const eServiceReference &ref, ePtr<iPlayableService> &ptr)
437 {
438         ePtr<eDVBService> service;
439         int r = lookupService(service, ref);
440         if (r)
441                 service = 0;
442                 // check resources...
443         ptr = new eDVBServicePlay(ref, service);
444         return 0;
445 }
446
447 RESULT eServiceFactoryDVB::record(const eServiceReference &ref, ePtr<iRecordableService> &ptr)
448 {
449         if (ref.path.empty())
450         {
451                 ptr = new eDVBServiceRecord((eServiceReferenceDVB&)ref);
452                 return 0;
453         } else
454         {
455                 ptr = 0;
456                 return -1;
457         }
458 }
459
460 RESULT eServiceFactoryDVB::list(const eServiceReference &ref, ePtr<iListableService> &ptr)
461 {
462         ePtr<eDVBServiceList> list = new eDVBServiceList(ref);
463         if (list->startQuery())
464         {
465                 ptr = 0;
466                 return -1;
467         }
468         
469         ptr = list;
470         return 0;
471 }
472
473 RESULT eServiceFactoryDVB::info(const eServiceReference &ref, ePtr<iStaticServiceInformation> &ptr)
474 {
475         /* is a listable service? */
476         if ((ref.flags & eServiceReference::flagDirectory) == eServiceReference::flagDirectory) // bouquet
477         {
478                 if ( !ref.name.empty() )  // satellites or providers list
479                         ptr = new eStaticServiceDVBInformation;
480                 else // a dvb bouquet
481                         ptr = new eStaticServiceDVBBouquetInformation;
482         }
483         else if (!ref.path.empty()) /* do we have a PVR service? */
484                 ptr = new eStaticServiceDVBPVRInformation(ref);
485         else // normal dvb service
486         {
487                 ePtr<eDVBService> service;
488                 if (lookupService(service, ref)) // no eDVBService avail for this reference ( Linkage Services... )
489                         ptr = new eStaticServiceDVBInformation;
490                 else
491                         /* eDVBService has the iStaticServiceInformation interface, so we pass it here. */
492                         ptr = service;
493         }
494         return 0;
495 }
496
497 RESULT eServiceFactoryDVB::offlineOperations(const eServiceReference &ref, ePtr<iServiceOfflineOperations> &ptr)
498 {
499         if (ref.path.empty())
500         {
501                 ptr = 0;
502                 return -1;
503         } else
504         {
505                 ptr = new eDVBPVRServiceOfflineOperations(ref);
506                 return 0;
507         }
508 }
509
510 RESULT eServiceFactoryDVB::lookupService(ePtr<eDVBService> &service, const eServiceReference &ref)
511 {
512                         // TODO: handle the listing itself
513         // if (ref.... == -1) .. return "... bouquets ...";
514         // could be also done in another serviceFactory (with seperate ID) to seperate actual services and lists
515                         // TODO: cache
516         ePtr<iDVBChannelList> db;
517         ePtr<eDVBResourceManager> res;
518         
519         int err;
520         if ((err = eDVBResourceManager::getInstance(res)) != 0)
521         {
522                 eDebug("no resource manager");
523                 return err;
524         }
525         if ((err = res->getChannelList(db)) != 0)
526         {
527                 eDebug("no channel list");
528                 return err;
529         }
530         
531                 /* we are sure to have a ..DVB reference as the info() call was forwarded here according to it's ID. */
532         if ((err = db->getService((eServiceReferenceDVB&)ref, service)) != 0)
533         {
534                 eDebug("getService failed!");
535                 return err;
536         }
537
538         return 0;
539 }
540
541 eDVBServicePlay::eDVBServicePlay(const eServiceReference &ref, eDVBService *service): 
542         m_reference(ref), m_dvb_service(service), m_is_paused(0)
543 {
544         m_is_pvr = !ref.path.empty();
545         
546         m_timeshift_enabled = m_timeshift_active = 0;
547         m_skipmode = 0;
548         
549         CONNECT(m_service_handler.serviceEvent, eDVBServicePlay::serviceEvent);
550         CONNECT(m_service_handler_timeshift.serviceEvent, eDVBServicePlay::serviceEventTimeshift);
551         CONNECT(m_event_handler.m_eit_changed, eDVBServicePlay::gotNewEvent);
552
553         m_cuesheet_changed = 0;
554         m_cutlist_enabled = 1;
555 }
556
557 eDVBServicePlay::~eDVBServicePlay()
558 {
559 }
560
561 void eDVBServicePlay::gotNewEvent()
562 {
563 #if 0
564                 // debug only
565         ePtr<eServiceEvent> m_event_now, m_event_next;
566         getEvent(m_event_now, 0);
567         getEvent(m_event_next, 1);
568
569         if (m_event_now)
570                 eDebug("now running: %s (%d seconds :)", m_event_now->m_event_name.c_str(), m_event_now->m_duration);
571         if (m_event_next)
572                 eDebug("next running: %s (%d seconds :)", m_event_next->m_event_name.c_str(), m_event_next->m_duration);
573 #endif
574         m_event((iPlayableService*)this, evUpdatedEventInfo);
575 }
576
577 void eDVBServicePlay::serviceEvent(int event)
578 {
579         switch (event)
580         {
581         case eDVBServicePMTHandler::eventTuned:
582         {
583                 ePtr<iDVBDemux> m_demux;
584                 if (!m_service_handler.getDataDemux(m_demux))
585                 {
586                         eServiceReferenceDVB &ref = (eServiceReferenceDVB&) m_reference;
587                         int sid = ref.getParentServiceID().get();
588                         if (!sid)
589                                 sid = ref.getServiceID().get();
590                         if ( ref.getParentTransportStreamID().get() &&
591                                 ref.getParentTransportStreamID() != ref.getTransportStreamID() )
592                                 m_event_handler.startOther(m_demux, sid);
593                         else
594                                 m_event_handler.start(m_demux, sid);
595                 }
596                 break;
597         }
598         case eDVBServicePMTHandler::eventTuneFailed:
599         {
600                 eDebug("DVB service failed to tune");
601                 m_event((iPlayableService*)this, evTuneFailed);
602                 break;
603         }
604         case eDVBServicePMTHandler::eventNewProgramInfo:
605         {
606                 eDebug("eventNewProgramInfo %d %d", m_timeshift_enabled, m_timeshift_active);
607                 if (m_timeshift_enabled)
608                         updateTimeshiftPids();
609                 if (!m_timeshift_active)
610                         updateDecoder();
611                 if (m_first_program_info && m_is_pvr)
612                 {
613                         m_first_program_info = 0;
614                         seekTo(0);
615                 }
616                 m_event((iPlayableService*)this, evUpdatedInfo);
617                 break;
618         }
619         case eDVBServicePMTHandler::eventEOF:
620                 m_event((iPlayableService*)this, evEOF);
621                 break;
622         case eDVBServicePMTHandler::eventSOF:
623                 m_event((iPlayableService*)this, evSOF);
624                 break;
625         }
626 }
627
628 void eDVBServicePlay::serviceEventTimeshift(int event)
629 {
630         switch (event)
631         {
632         case eDVBServicePMTHandler::eventNewProgramInfo:
633                 if (m_timeshift_active)
634                         updateDecoder();
635                 break;
636         case eDVBServicePMTHandler::eventEOF:
637                 switchToLive();
638                 break;
639         }
640 }
641
642 RESULT eDVBServicePlay::start()
643 {
644         int r;
645                 /* in pvr mode, we only want to use one demux. in tv mode, we're using 
646                    two (one for decoding, one for data source), as we must be prepared
647                    to start recording from the data demux. */
648         m_cue = new eCueSheet();
649
650         m_first_program_info = 1;
651         eServiceReferenceDVB &service = (eServiceReferenceDVB&)m_reference;
652         r = m_service_handler.tune(service, m_is_pvr, m_cue);
653         
654                 /* inject EIT if there is a stored one */
655         if (m_is_pvr)
656         {
657                 std::string filename = service.path;
658                 filename.erase(filename.length()-2, 2);
659                 filename+="eit";
660                 int fd = ::open( filename.c_str(), O_RDONLY );
661                 if ( fd > -1 )
662                 {
663                         __u8 buf[4096];
664                         int rd = ::read(fd, buf, 4096);
665                         ::close(fd);
666                         if ( rd > 12 /*EIT_LOOP_SIZE*/ )
667                         {
668                                 Event ev(buf);
669                                 ePtr<eServiceEvent> event = new eServiceEvent;
670                                 ePtr<eServiceEvent> empty;
671                                 event->parseFrom(&ev, (service.getTransportStreamID().get()<<16)|service.getOriginalNetworkID().get());
672                                 m_event_handler.inject(event, 0);
673                                 m_event_handler.inject(empty, 1);
674                                 eDebug("injected");
675                         }
676                 }
677         }
678         
679         if (m_is_pvr)
680                 loadCuesheet();
681
682         m_event(this, evStart);
683         m_event((iPlayableService*)this, evSeekableStatusChanged);
684         return 0;
685 }
686
687 RESULT eDVBServicePlay::stop()
688 {
689         stopTimeshift(); /* in case timeshift was enabled, remove buffer etc. */
690
691         m_service_handler_timeshift.free();
692         m_service_handler.free();
693         
694         if (m_is_pvr && m_cuesheet_changed)
695                 saveCuesheet();
696         
697         return 0;
698 }
699
700 RESULT eDVBServicePlay::connectEvent(const Slot2<void,iPlayableService*,int> &event, ePtr<eConnection> &connection)
701 {
702         connection = new eConnection((iPlayableService*)this, m_event.connect(event));
703         return 0;
704 }
705
706 RESULT eDVBServicePlay::pause(ePtr<iPauseableService> &ptr)
707 {
708                 /* note: we check for timeshift to be enabled,
709                    not neccessary active. if you pause when timeshift
710                    is not active, you should activate it when unpausing */
711         if ((!m_is_pvr) && (!m_timeshift_enabled))
712         {
713                 ptr = 0;
714                 return -1;
715         }
716
717         ptr = this;
718         return 0;
719 }
720
721 RESULT eDVBServicePlay::setSlowMotion(int ratio)
722 {
723         if (m_decoder)
724                 return m_decoder->setSlowMotion(ratio);
725         else
726                 return -1;
727 }
728
729 RESULT eDVBServicePlay::setFastForward(int ratio)
730 {
731         int skipmode, ffratio;
732         
733         if (ratio > 8)
734         {
735                 skipmode = ratio;
736                 ffratio = 1;
737         } else if (ratio > 0)
738         {
739                 skipmode = 0;
740                 ffratio = ratio;
741         } else if (!ratio)
742         {
743                 skipmode = 0;
744                 ffratio = 0;
745         } else // if (ratio < 0)
746         {
747                 skipmode = ratio;
748                 ffratio = 1;
749         }
750
751         if (m_skipmode != skipmode)
752         {
753                 eDebug("setting cue skipmode to %d", skipmode);
754                 if (m_cue)
755                         m_cue->setSkipmode(skipmode * 90000); /* convert to 90000 per second */
756         }
757         
758         m_skipmode = skipmode;
759         
760         if (!m_decoder)
761                 return -1;
762
763         return m_decoder->setFastForward(ffratio);
764 }
765     
766 RESULT eDVBServicePlay::seek(ePtr<iSeekableService> &ptr)
767 {
768         if (m_is_pvr || m_timeshift_enabled)
769         {
770                 ptr = this;
771                 return 0;
772         }
773         
774         ptr = 0;
775         return -1;
776 }
777
778         /* TODO: when timeshift is enabled but not active, this doesn't work. */
779 RESULT eDVBServicePlay::getLength(pts_t &len)
780 {
781         ePtr<iDVBPVRChannel> pvr_channel;
782         
783         if ((m_timeshift_enabled ? m_service_handler_timeshift : m_service_handler).getPVRChannel(pvr_channel))
784                 return -1;
785         
786         return pvr_channel->getLength(len);
787 }
788
789 RESULT eDVBServicePlay::pause()
790 {
791         if (!m_is_paused && m_decoder)
792         {
793                 m_is_paused = 1;
794                 return m_decoder->freeze(0);
795         } else
796                 return -1;
797 }
798
799 RESULT eDVBServicePlay::unpause()
800 {
801         if (m_is_paused && m_decoder)
802         {
803                 m_is_paused = 0;
804                 return m_decoder->unfreeze();
805         } else
806                 return -1;
807 }
808
809 RESULT eDVBServicePlay::seekTo(pts_t to)
810 {
811         eDebug("eDVBServicePlay::seekTo: jump %lld", to);
812         
813         if (!m_decode_demux)
814                 return -1;
815
816         ePtr<iDVBPVRChannel> pvr_channel;
817         
818         if ((m_timeshift_enabled ? m_service_handler_timeshift : m_service_handler).getPVRChannel(pvr_channel))
819                 return -1;
820         
821         if (!m_cue)
822                 return -1;
823         
824         m_cue->seekTo(0, to);
825         return 0;
826 }
827
828 RESULT eDVBServicePlay::seekRelative(int direction, pts_t to)
829 {
830         eDebug("eDVBServicePlay::seekRelative: jump %d, %lld", direction, to);
831         
832         if (!m_decode_demux)
833                 return -1;
834
835         ePtr<iDVBPVRChannel> pvr_channel;
836         
837         if ((m_timeshift_enabled ? m_service_handler_timeshift : m_service_handler).getPVRChannel(pvr_channel))
838                 return -1;
839         
840         int mode = 1;
841         
842                         /* HACK until we have skip-AP api */
843         if ((to > 0) && (to < 100))
844                 mode = 2;
845         
846         to *= direction;
847         
848         if (!m_cue)
849                 return 0;
850         
851         m_cue->seekTo(mode, to);
852         return 0;
853 }
854
855 RESULT eDVBServicePlay::getPlayPosition(pts_t &pos)
856 {
857         ePtr<iDVBPVRChannel> pvr_channel;
858         
859         if (!m_decode_demux)
860                 return -1;
861         
862         if ((m_timeshift_enabled ? m_service_handler_timeshift : m_service_handler).getPVRChannel(pvr_channel))
863                 return -1;
864         
865         int r = 0;
866
867                 /* if there is a decoder, use audio or video PTS */
868         if (m_decoder)
869         {
870                 r = m_decoder->getPTS(0, pos);
871                 if (r)
872                         return r;
873         }
874         
875                 /* fixup */
876         return pvr_channel->getCurrentPosition(m_decode_demux, pos, m_decoder ? 1 : 0);
877 }
878
879 RESULT eDVBServicePlay::setTrickmode(int trick)
880 {
881         if (m_decoder)
882                 m_decoder->setTrickmode(trick);
883         return 0;
884 }
885
886 RESULT eDVBServicePlay::isCurrentlySeekable()
887 {
888         return m_is_pvr || m_timeshift_active;
889 }
890
891 RESULT eDVBServicePlay::frontendStatusInfo(ePtr<iFrontendStatusInformation> &ptr)
892 {
893         ptr = this;
894         return 0;
895 }
896
897 RESULT eDVBServicePlay::info(ePtr<iServiceInformation> &ptr)
898 {
899         ptr = this;
900         return 0;
901 }
902
903 RESULT eDVBServicePlay::audioTracks(ePtr<iAudioTrackSelection> &ptr)
904 {
905         ptr = this;
906         return 0;
907 }
908
909 RESULT eDVBServicePlay::subServices(ePtr<iSubserviceList> &ptr)
910 {
911         ptr = this;
912         return 0;
913 }
914
915 RESULT eDVBServicePlay::timeshift(ePtr<iTimeshiftService> &ptr)
916 {
917         ptr = 0;
918         if (m_timeshift_enabled || !m_is_pvr)
919         {
920                 if (!m_timeshift_enabled)
921                 {
922                                 /* we need enough diskspace */
923                         struct statfs fs;
924                         if (statfs(TSPATH "/.", &fs) < 0)
925                         {
926                                 eDebug("statfs failed!");
927                                 return -2;
928                         }
929                 
930                         if (((off_t)fs.f_bavail) * ((off_t)fs.f_bsize) < 1024*1024*1024LL)
931                         {
932                                 eDebug("not enough diskspace for timeshift! (less than 1GB)");
933                                 return -3;
934                         }
935                 }
936                 ptr = this;
937                 return 0;
938         }
939         return -1;
940 }
941
942 RESULT eDVBServicePlay::cueSheet(ePtr<iCueSheet> &ptr)
943 {
944         if (m_is_pvr)
945         {
946                 ptr = this;
947                 return 0;
948         }
949         ptr = 0;
950         return -1;
951 }
952
953 RESULT eDVBServicePlay::getName(std::string &name)
954 {
955         if (m_is_pvr)
956         {
957                 ePtr<iStaticServiceInformation> i = new eStaticServiceDVBPVRInformation(m_reference);
958                 return i->getName(m_reference, name);
959         }
960         if (m_dvb_service)
961         {
962                 m_dvb_service->getName(m_reference, name);
963                 if (name.empty())
964                         name = "(...)";
965         }
966         else if (!m_reference.name.empty())
967                 eStaticServiceDVBInformation().getName(m_reference, name);
968         else
969                 name = "DVB service";
970         return 0;
971 }
972
973 RESULT eDVBServicePlay::getEvent(ePtr<eServiceEvent> &evt, int nownext)
974 {
975         return m_event_handler.getEvent(evt, nownext);
976 }
977
978 int eDVBServicePlay::getInfo(int w)
979 {
980         eDVBServicePMTHandler::program program;
981
982         if (m_service_handler.getProgramInfo(program))
983                 return -1;
984         
985         switch (w)
986         {
987         case sAspect:
988                 if (!program.videoStreams.empty() && program.videoStreams[0].component_tag != -1)
989                 {
990                         ePtr<eServiceEvent> evt;
991                         if (!m_event_handler.getEvent(evt, 0))
992                         {
993                                 ePtr<eComponentData> data;
994                                 if (!evt->getComponentData(data, program.videoStreams[0].component_tag))
995                                 {
996                                         if ( data->getStreamContent() == 1 )
997                                         {
998                                                 switch(data->getComponentType())
999                                                 {
1000                                                         // SD
1001                                                         case 1: // 4:3 SD PAL
1002                                                         case 2:
1003                                                         case 3: // 16:9 SD PAL
1004                                                         case 4: // > 16:9 PAL
1005                                                         case 5: // 4:3 SD NTSC
1006                                                         case 6: 
1007                                                         case 7: // 16:9 SD NTSC
1008                                                         case 8: // > 16:9 NTSC
1009
1010                                                         // HD
1011                                                         case 9: // 4:3 HD PAL
1012                                                         case 0xA:
1013                                                         case 0xB: // 16:9 HD PAL
1014                                                         case 0xC: // > 16:9 HD PAL
1015                                                         case 0xD: // 4:3 HD NTSC
1016                                                         case 0xE:
1017                                                         case 0xF: // 16:9 HD NTSC
1018                                                         case 0x10: // > 16:9 HD PAL
1019                                                                 return data->getComponentType();
1020                                                 }
1021                                         }
1022                                 }
1023                         }
1024                 }
1025                 return -1;
1026         case sIsCrypted: return program.isCrypted;
1027         case sVideoPID: if (program.videoStreams.empty()) return -1; return program.videoStreams[0].pid;
1028         case sAudioPID: if (program.audioStreams.empty()) return -1; return program.audioStreams[m_current_audio_stream].pid;
1029         case sPCRPID: return program.pcrPid;
1030         case sPMTPID: return program.pmtPid;
1031         case sTXTPID: return program.textPid;
1032         case sSID: return ((const eServiceReferenceDVB&)m_reference).getServiceID().get();
1033         case sONID: return ((const eServiceReferenceDVB&)m_reference).getOriginalNetworkID().get();
1034         case sTSID: return ((const eServiceReferenceDVB&)m_reference).getTransportStreamID().get();
1035         case sNamespace: return ((const eServiceReferenceDVB&)m_reference).getDVBNamespace().get();
1036         case sProvider: if (!m_dvb_service) return -1; return -2;
1037         default:
1038                 return -1;
1039         }
1040 }
1041
1042 std::string eDVBServicePlay::getInfoString(int w)
1043 {       
1044         switch (w)
1045         {
1046         case sProvider:
1047                 if (!m_dvb_service) return "";
1048                 return m_dvb_service->m_provider_name;
1049         default:
1050                 return "";
1051         }
1052 }
1053
1054 int eDVBServicePlay::getNumberOfTracks()
1055 {
1056         eDVBServicePMTHandler::program program;
1057         if (m_service_handler.getProgramInfo(program))
1058                 return 0;
1059         return program.audioStreams.size();
1060 }
1061
1062 RESULT eDVBServicePlay::selectTrack(unsigned int i)
1063 {
1064         int ret = selectAudioStream(i);
1065
1066         if (m_decoder->start())
1067                 return -5;
1068
1069         return ret;
1070 }
1071
1072 RESULT eDVBServicePlay::getTrackInfo(struct iAudioTrackInfo &info, unsigned int i)
1073 {
1074         eDVBServicePMTHandler::program program;
1075
1076         if (m_service_handler.getProgramInfo(program))
1077                 return -1;
1078         
1079         if (i >= program.audioStreams.size())
1080                 return -2;
1081         
1082         if (program.audioStreams[i].type == eDVBServicePMTHandler::audioStream::atMPEG)
1083                 info.m_description = "MPEG";
1084         else if (program.audioStreams[i].type == eDVBServicePMTHandler::audioStream::atAC3)
1085                 info.m_description = "AC3";
1086         else  if (program.audioStreams[i].type == eDVBServicePMTHandler::audioStream::atDTS)
1087                 info.m_description = "DTS";
1088         else
1089                 info.m_description = "???";
1090
1091         if (program.audioStreams[i].component_tag != -1)
1092         {
1093                 ePtr<eServiceEvent> evt;
1094                 if (!m_event_handler.getEvent(evt, 0))
1095                 {
1096                         ePtr<eComponentData> data;
1097                         if (!evt->getComponentData(data, program.audioStreams[i].component_tag))
1098                                 info.m_language = data->getText();
1099                 }
1100         }
1101
1102         if (info.m_language.empty())
1103                 info.m_language = program.audioStreams[i].language_code;
1104         
1105         return 0;
1106 }
1107
1108 int eDVBServicePlay::selectAudioStream(int i)
1109 {
1110         eDVBServicePMTHandler::program program;
1111
1112         if (m_service_handler.getProgramInfo(program))
1113                 return -1;
1114         
1115         if ((unsigned int)i >= program.audioStreams.size())
1116                 return -2;
1117         
1118         if (!m_decoder)
1119                 return -3;
1120         
1121         if (m_decoder->setAudioPID(program.audioStreams[i].pid, program.audioStreams[i].type))
1122                 return -4;
1123
1124         if (m_dvb_service && !m_is_pvr)
1125         {
1126                 if (program.audioStreams[i].type == eDVBAudio::aMPEG)
1127                 {
1128                         m_dvb_service->setCachePID(eDVBService::cAPID, program.audioStreams[i].pid);
1129                         m_dvb_service->setCachePID(eDVBService::cAC3PID, -1);
1130                 }       else
1131                 {
1132                         m_dvb_service->setCachePID(eDVBService::cAPID, -1);
1133                         m_dvb_service->setCachePID(eDVBService::cAC3PID, program.audioStreams[i].pid);
1134                 }
1135         }
1136
1137         m_current_audio_stream = i;
1138
1139         return 0;
1140 }
1141
1142 int eDVBServicePlay::getFrontendInfo(int w)
1143 {
1144         if (m_is_pvr)
1145                 return 0;
1146         eUsePtr<iDVBChannel> channel;
1147         if(m_service_handler.getChannel(channel))
1148                 return 0;
1149         ePtr<iDVBFrontend> fe;
1150         if(channel->getFrontend(fe))
1151                 return 0;
1152         return fe->readFrontendData(w);
1153 }
1154
1155 PyObject *eDVBServicePlay::getFrontendTransponderData()
1156 {
1157         PyObject *ret=0;
1158
1159         eUsePtr<iDVBChannel> channel;
1160         if(!m_service_handler.getChannel(channel))
1161         {
1162                 ePtr<iDVBFrontend> fe;
1163                 if(!channel->getFrontend(fe))
1164                         ret = fe->readTransponderData();
1165         }
1166
1167         if (!ret)
1168         {
1169                 ret = Py_None;
1170                 Py_INCREF(ret);
1171         }
1172         return ret;
1173 }
1174
1175 int eDVBServicePlay::getNumberOfSubservices()
1176 {
1177         ePtr<eServiceEvent> evt;
1178         if (!m_event_handler.getEvent(evt, 0))
1179                 return evt->getNumOfLinkageServices();
1180         return 0;
1181 }
1182
1183 RESULT eDVBServicePlay::getSubservice(eServiceReference &sub, unsigned int n)
1184 {
1185         ePtr<eServiceEvent> evt;
1186         if (!m_event_handler.getEvent(evt, 0))
1187         {
1188                 if (!evt->getLinkageService(sub, m_reference, n))
1189                         return 0;
1190         }
1191         sub.type=eServiceReference::idInvalid;
1192         return -1;
1193 }
1194
1195 RESULT eDVBServicePlay::startTimeshift()
1196 {
1197         ePtr<iDVBDemux> demux;
1198         
1199         eDebug("Start timeshift!");
1200         
1201         if (m_timeshift_enabled)
1202                 return -1;
1203         
1204                 /* start recording with the data demux. */
1205         if (m_service_handler.getDataDemux(demux))
1206                 return -2;
1207
1208         demux->createTSRecorder(m_record);
1209         if (!m_record)
1210                 return -3;
1211
1212         char templ[]=TSPATH "/timeshift.XXXXXX";
1213         m_timeshift_fd = mkstemp(templ);
1214         m_timeshift_file = templ;
1215         
1216         eDebug("recording to %s", templ);
1217         
1218         if (m_timeshift_fd < 0)
1219         {
1220                 m_record = 0;
1221                 return -4;
1222         }
1223                 
1224         m_record->setTargetFD(m_timeshift_fd);
1225
1226         m_timeshift_enabled = 1;
1227         
1228         updateTimeshiftPids();
1229         m_record->start();
1230
1231         return 0;
1232 }
1233
1234 RESULT eDVBServicePlay::stopTimeshift()
1235 {
1236         if (!m_timeshift_enabled)
1237                 return -1;
1238         
1239         switchToLive();
1240         
1241         m_timeshift_enabled = 0;
1242         
1243         m_record->stop();
1244         m_record = 0;
1245         
1246         close(m_timeshift_fd);
1247         eDebug("remove timeshift file");
1248         remove(m_timeshift_file.c_str());
1249         
1250         return 0;
1251 }
1252
1253 int eDVBServicePlay::isTimeshiftActive()
1254 {
1255         return m_timeshift_enabled && m_timeshift_active;
1256 }
1257
1258 RESULT eDVBServicePlay::activateTimeshift()
1259 {
1260         if (!m_timeshift_enabled)
1261                 return -1;
1262         
1263         if (!m_timeshift_active)
1264         {
1265                 switchToTimeshift();
1266                 return 0;
1267         }
1268         
1269         return -2;
1270 }
1271
1272 PyObject *eDVBServicePlay::getCutList()
1273 {
1274         PyObject *list = PyList_New(0);
1275         
1276         for (std::multiset<struct cueEntry>::iterator i(m_cue_entries.begin()); i != m_cue_entries.end(); ++i)
1277         {
1278                 PyObject *tuple = PyTuple_New(2);
1279                 PyTuple_SetItem(tuple, 0, PyLong_FromLongLong(i->where));
1280                 PyTuple_SetItem(tuple, 1, PyInt_FromLong(i->what));
1281                 PyList_Append(list, tuple);
1282                 Py_DECREF(tuple);
1283         }
1284         
1285         return list;
1286 }
1287
1288 void eDVBServicePlay::setCutList(PyObject *list)
1289 {
1290         if (!PyList_Check(list))
1291                 return;
1292         int size = PyList_Size(list);
1293         int i;
1294         
1295         m_cue_entries.clear();
1296         
1297         for (i=0; i<size; ++i)
1298         {
1299                 PyObject *tuple = PyList_GetItem(list, i);
1300                 if (!PyTuple_Check(tuple))
1301                 {
1302                         eDebug("non-tuple in cutlist");
1303                         continue;
1304                 }
1305                 if (PyTuple_Size(tuple) != 2)
1306                 {
1307                         eDebug("cutlist entries need to be a 2-tuple");
1308                         continue;
1309                 }
1310                 PyObject *ppts = PyTuple_GetItem(tuple, 0), *ptype = PyTuple_GetItem(tuple, 1);
1311                 if (!(PyLong_Check(ppts) && PyInt_Check(ptype)))
1312                 {
1313                         eDebug("cutlist entries need to be (pts, type)-tuples (%d %d)", PyLong_Check(ppts), PyInt_Check(ptype));
1314                         continue;
1315                 }
1316                 pts_t pts = PyLong_AsLongLong(ppts);
1317                 int type = PyInt_AsLong(ptype);
1318                 m_cue_entries.insert(cueEntry(pts, type));
1319                 eDebug("adding %08llx, %d", pts, type);
1320         }
1321         m_cuesheet_changed = 1;
1322         
1323         cutlistToCuesheet();
1324         m_event((iPlayableService*)this, evCuesheetChanged);
1325 }
1326
1327 void eDVBServicePlay::setCutListEnable(int enable)
1328 {
1329         m_cutlist_enabled = enable;
1330         cutlistToCuesheet();
1331 }
1332
1333 void eDVBServicePlay::updateTimeshiftPids()
1334 {
1335         if (!m_record)
1336                 return;
1337         
1338         eDVBServicePMTHandler::program program;
1339         if (m_service_handler.getProgramInfo(program))
1340                 return;
1341         else
1342         {
1343                 std::set<int> pids_to_record;
1344                 pids_to_record.insert(0); // PAT
1345                 if (program.pmtPid != -1)
1346                         pids_to_record.insert(program.pmtPid); // PMT
1347
1348                 if (program.textPid != -1)
1349                         pids_to_record.insert(program.textPid); // Videotext
1350
1351                 for (std::vector<eDVBServicePMTHandler::videoStream>::const_iterator
1352                         i(program.videoStreams.begin()); 
1353                         i != program.videoStreams.end(); ++i)
1354                         pids_to_record.insert(i->pid);
1355
1356                 for (std::vector<eDVBServicePMTHandler::audioStream>::const_iterator
1357                         i(program.audioStreams.begin()); 
1358                         i != program.audioStreams.end(); ++i)
1359                                 pids_to_record.insert(i->pid);
1360
1361                 std::set<int> new_pids, obsolete_pids;
1362                 
1363                 std::set_difference(pids_to_record.begin(), pids_to_record.end(), 
1364                                 m_pids_active.begin(), m_pids_active.end(),
1365                                 std::inserter(new_pids, new_pids.begin()));
1366                 
1367                 std::set_difference(
1368                                 m_pids_active.begin(), m_pids_active.end(),
1369                                 pids_to_record.begin(), pids_to_record.end(), 
1370                                 std::inserter(new_pids, new_pids.begin())
1371                                 );
1372
1373                 for (std::set<int>::iterator i(new_pids.begin()); i != new_pids.end(); ++i)
1374                         m_record->addPID(*i);
1375
1376                 for (std::set<int>::iterator i(obsolete_pids.begin()); i != obsolete_pids.end(); ++i)
1377                         m_record->removePID(*i);
1378         }
1379 }
1380
1381 void eDVBServicePlay::switchToLive()
1382 {
1383         if (!m_timeshift_active)
1384                 return;
1385         
1386         m_decoder = 0;
1387         m_decode_demux = 0;
1388                 /* free the timeshift service handler, we need the resources */
1389         m_service_handler_timeshift.free();
1390         m_timeshift_active = 0;
1391         
1392         m_event((iPlayableService*)this, evSeekableStatusChanged);
1393         
1394         updateDecoder();
1395 }
1396
1397 void eDVBServicePlay::switchToTimeshift()
1398 {
1399         if (m_timeshift_active)
1400                 return;
1401         
1402         m_decode_demux = 0;
1403         m_decoder = 0;
1404         
1405         m_timeshift_active = 1;
1406
1407         m_event((iPlayableService*)this, evSeekableStatusChanged);
1408         
1409         eServiceReferenceDVB r = (eServiceReferenceDVB&)m_reference;
1410         r.path = m_timeshift_file;
1411         
1412         m_service_handler_timeshift.tune(r, 1, m_cue); /* use the decoder demux for everything */
1413 }
1414
1415 void eDVBServicePlay::updateDecoder()
1416 {
1417         int vpid = -1, apid = -1, apidtype = -1, pcrpid = -1, tpid = -1;
1418         eDVBServicePMTHandler &h = m_timeshift_active ? m_service_handler_timeshift : m_service_handler;
1419
1420         eDVBServicePMTHandler::program program;
1421         if (h.getProgramInfo(program))
1422                 eDebug("getting program info failed.");
1423         else
1424         {
1425                 eDebugNoNewLine("have %d video stream(s)", program.videoStreams.size());
1426                 if (!program.videoStreams.empty())
1427                 {
1428                         eDebugNoNewLine(" (");
1429                         for (std::vector<eDVBServicePMTHandler::videoStream>::const_iterator
1430                                 i(program.videoStreams.begin()); 
1431                                 i != program.videoStreams.end(); ++i)
1432                         {
1433                                 if (vpid == -1)
1434                                         vpid = i->pid;
1435                                 if (i != program.videoStreams.begin())
1436                                         eDebugNoNewLine(", ");
1437                                 eDebugNoNewLine("%04x", i->pid);
1438                         }
1439                         eDebugNoNewLine(")");
1440                 }
1441                 eDebugNoNewLine(", and %d audio stream(s)", program.audioStreams.size());
1442                 if (!program.audioStreams.empty())
1443                 {
1444                         eDebugNoNewLine(" (");
1445                         for (std::vector<eDVBServicePMTHandler::audioStream>::const_iterator
1446                                 i(program.audioStreams.begin()); 
1447                                 i != program.audioStreams.end(); ++i)
1448                         {
1449                                 if (apid == -1)
1450                                 {
1451                                         apid = i->pid;
1452                                         apidtype = i->type;
1453                                 }
1454                                 if (i != program.audioStreams.begin())
1455                                         eDebugNoNewLine(", ");
1456                                 eDebugNoNewLine("%04x", i->pid);
1457                         }
1458                         eDebugNoNewLine(")");
1459                 }
1460                 eDebugNoNewLine(", and the pcr pid is %04x", program.pcrPid);
1461                 pcrpid = program.pcrPid;
1462                 eDebug(", and the text pid is %04x", program.textPid);
1463                 tpid = program.textPid;
1464         }
1465
1466         if (!m_decoder)
1467         {
1468                 h.getDecodeDemux(m_decode_demux);
1469                 if (m_decode_demux)
1470                         m_decode_demux->getMPEGDecoder(m_decoder);
1471                 if (m_cue)
1472                         m_cue->setDecodingDemux(m_decode_demux, m_decoder);
1473         }
1474
1475         if (m_decoder)
1476         {
1477                 m_decoder->setVideoPID(vpid);
1478                 m_current_audio_stream = 0;
1479                 m_decoder->setAudioPID(apid, apidtype);
1480                 if (!(m_is_pvr || m_timeshift_active))
1481                         m_decoder->setSyncPCR(pcrpid);
1482                 else
1483                         m_decoder->setSyncPCR(-1);
1484                 m_decoder->setTextPID(tpid);
1485                 m_decoder->start();
1486 // how we can do this better?
1487 // update cache pid when the user changed the audio track or video track
1488 // TODO handling of difference audio types.. default audio types..
1489                                 
1490                 /* don't worry about non-existing services, nor pvr services */
1491                 if (m_dvb_service && !m_is_pvr)
1492                 {
1493                         if (apidtype == eDVBAudio::aMPEG)
1494                         {
1495                                 m_dvb_service->setCachePID(eDVBService::cAPID, apid);
1496                                 m_dvb_service->setCachePID(eDVBService::cAC3PID, -1);
1497                         }
1498                         else
1499                         {
1500                                 m_dvb_service->setCachePID(eDVBService::cAPID, -1);
1501                                 m_dvb_service->setCachePID(eDVBService::cAC3PID, apid);
1502                         }
1503                         m_dvb_service->setCachePID(eDVBService::cVPID, vpid);
1504                         m_dvb_service->setCachePID(eDVBService::cPCRPID, pcrpid);
1505                         m_dvb_service->setCachePID(eDVBService::cTPID, tpid);
1506                 }
1507         }
1508 }
1509
1510 void eDVBServicePlay::loadCuesheet()
1511 {
1512         std::string filename = m_reference.path + ".cuts";
1513         
1514         m_cue_entries.clear();
1515
1516         FILE *f = fopen(filename.c_str(), "rb");
1517
1518         if (f)
1519         {
1520                 eDebug("loading cuts..");
1521                 while (1)
1522                 {
1523                         unsigned long long where;
1524                         unsigned int what;
1525                         
1526                         if (!fread(&where, sizeof(where), 1, f))
1527                                 break;
1528                         if (!fread(&what, sizeof(what), 1, f))
1529                                 break;
1530                         
1531 #if BYTE_ORDER == LITTLE_ENDIAN
1532                         where = bswap_64(where);
1533 #endif
1534                         what = ntohl(what);
1535                         
1536                         if (what > 2)
1537                                 break;
1538                         
1539                         m_cue_entries.insert(cueEntry(where, what));
1540                 }
1541                 fclose(f);
1542                 eDebug("%d entries", m_cue_entries.size());
1543         } else
1544                 eDebug("cutfile not found!");
1545         
1546         m_cuesheet_changed = 0;
1547         cutlistToCuesheet();
1548         m_event((iPlayableService*)this, evCuesheetChanged);
1549 }
1550
1551 void eDVBServicePlay::saveCuesheet()
1552 {
1553         std::string filename = m_reference.path + ".cuts";
1554         
1555         FILE *f = fopen(filename.c_str(), "wb");
1556
1557         if (f)
1558         {
1559                 unsigned long long where;
1560                 int what;
1561
1562                 for (std::multiset<cueEntry>::iterator i(m_cue_entries.begin()); i != m_cue_entries.end(); ++i)
1563                 {
1564 #if BYTE_ORDER == BIG_ENDIAN
1565                         where = i->where;
1566 #else
1567                         where = bswap_64(i->where);
1568 #endif
1569                         what = htonl(i->what);
1570                         fwrite(&where, sizeof(where), 1, f);
1571                         fwrite(&what, sizeof(what), 1, f);
1572                         
1573                 }
1574                 fclose(f);
1575         }
1576         
1577         m_cuesheet_changed = 0;
1578 }
1579
1580 void eDVBServicePlay::cutlistToCuesheet()
1581 {
1582         if (!m_cue)
1583         {
1584                 eDebug("no cue sheet");
1585                 return;
1586         }       
1587         m_cue->clear();
1588         
1589         if (!m_cutlist_enabled)
1590         {
1591                 m_cue->commitSpans();
1592                 eDebug("cutlists where disabled");
1593                 return;
1594         }
1595
1596         pts_t in = 0, out = 0, length = 0;
1597         
1598         getLength(length);
1599                 
1600         std::multiset<cueEntry>::iterator i(m_cue_entries.begin());
1601         
1602         while (1)
1603         {
1604                 if (i == m_cue_entries.end())
1605                         out = length;
1606                 else {
1607                         if (i->what == 0) /* in */
1608                         {
1609                                 in = i++->where;
1610                                 continue;
1611                         } else if (i->what == 1) /* out */
1612                                 out = i++->where;
1613                         else /* mark */
1614                         {
1615                                 i++;
1616                                 continue;
1617                         }
1618                 }
1619                 
1620                 if (in != out)
1621                         m_cue->addSourceSpan(in, out);
1622                 
1623                 in = length;
1624                 
1625                 if (i == m_cue_entries.end())
1626                         break;
1627         }
1628         m_cue->commitSpans();
1629 }
1630
1631 DEFINE_REF(eDVBServicePlay)
1632
1633 eAutoInitPtr<eServiceFactoryDVB> init_eServiceFactoryDVB(eAutoInitNumbers::service+1, "eServiceFactoryDVB");