0fdeb743213ac957576dc0db29548c0bf91097a5
[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::getFrontendData(bool original)
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                 {
1165                         ret = fe->readTransponderData(original);
1166                         if (ret)
1167                         {
1168                                 ePtr<iDVBFrontendParameters> feparm;
1169                                 channel->getCurrentFrontendParameters(feparm);
1170                                 if (feparm)
1171                                 {
1172                                         eDVBFrontendParametersSatellite osat;
1173                                         if (!feparm->getDVBS(osat))
1174                                         {
1175                                                 void PutToDict(PyObject *dict, const char*key, long value);
1176                                                 PutToDict(ret, "orbital_position", osat.orbital_position);
1177                                                 const char *tmp = "unknown";
1178                                                 switch(osat.polarisation)
1179                                                 {
1180                                                         case eDVBFrontendParametersSatellite::Polarisation::Horizontal: tmp="horizontal"; break;
1181                                                         case eDVBFrontendParametersSatellite::Polarisation::Vertical: tmp="vertical"; break;
1182                                                         case eDVBFrontendParametersSatellite::Polarisation::CircularLeft: tmp="circular_left"; break;
1183                                                         case eDVBFrontendParametersSatellite::Polarisation::CircularRight: tmp="circular_right"; break;
1184                                                         default:break;
1185                                                 }
1186                                                 PutToDict(ret, "polarization", osat.polarisation);
1187                                         }
1188                                 }
1189                         }
1190                 }
1191         }
1192         if (!ret)
1193         {
1194                 ret = Py_None;
1195                 Py_INCREF(ret);
1196         }
1197         return ret;
1198 }
1199
1200 int eDVBServicePlay::getNumberOfSubservices()
1201 {
1202         ePtr<eServiceEvent> evt;
1203         if (!m_event_handler.getEvent(evt, 0))
1204                 return evt->getNumOfLinkageServices();
1205         return 0;
1206 }
1207
1208 RESULT eDVBServicePlay::getSubservice(eServiceReference &sub, unsigned int n)
1209 {
1210         ePtr<eServiceEvent> evt;
1211         if (!m_event_handler.getEvent(evt, 0))
1212         {
1213                 if (!evt->getLinkageService(sub, m_reference, n))
1214                         return 0;
1215         }
1216         sub.type=eServiceReference::idInvalid;
1217         return -1;
1218 }
1219
1220 RESULT eDVBServicePlay::startTimeshift()
1221 {
1222         ePtr<iDVBDemux> demux;
1223         
1224         eDebug("Start timeshift!");
1225         
1226         if (m_timeshift_enabled)
1227                 return -1;
1228         
1229                 /* start recording with the data demux. */
1230         if (m_service_handler.getDataDemux(demux))
1231                 return -2;
1232
1233         demux->createTSRecorder(m_record);
1234         if (!m_record)
1235                 return -3;
1236
1237         char templ[]=TSPATH "/timeshift.XXXXXX";
1238         m_timeshift_fd = mkstemp(templ);
1239         m_timeshift_file = templ;
1240         
1241         eDebug("recording to %s", templ);
1242         
1243         if (m_timeshift_fd < 0)
1244         {
1245                 m_record = 0;
1246                 return -4;
1247         }
1248                 
1249         m_record->setTargetFD(m_timeshift_fd);
1250
1251         m_timeshift_enabled = 1;
1252         
1253         updateTimeshiftPids();
1254         m_record->start();
1255
1256         return 0;
1257 }
1258
1259 RESULT eDVBServicePlay::stopTimeshift()
1260 {
1261         if (!m_timeshift_enabled)
1262                 return -1;
1263         
1264         switchToLive();
1265         
1266         m_timeshift_enabled = 0;
1267         
1268         m_record->stop();
1269         m_record = 0;
1270         
1271         close(m_timeshift_fd);
1272         eDebug("remove timeshift file");
1273         remove(m_timeshift_file.c_str());
1274         
1275         return 0;
1276 }
1277
1278 int eDVBServicePlay::isTimeshiftActive()
1279 {
1280         return m_timeshift_enabled && m_timeshift_active;
1281 }
1282
1283 RESULT eDVBServicePlay::activateTimeshift()
1284 {
1285         if (!m_timeshift_enabled)
1286                 return -1;
1287         
1288         if (!m_timeshift_active)
1289         {
1290                 switchToTimeshift();
1291                 return 0;
1292         }
1293         
1294         return -2;
1295 }
1296
1297 PyObject *eDVBServicePlay::getCutList()
1298 {
1299         PyObject *list = PyList_New(0);
1300         
1301         for (std::multiset<struct cueEntry>::iterator i(m_cue_entries.begin()); i != m_cue_entries.end(); ++i)
1302         {
1303                 PyObject *tuple = PyTuple_New(2);
1304                 PyTuple_SetItem(tuple, 0, PyLong_FromLongLong(i->where));
1305                 PyTuple_SetItem(tuple, 1, PyInt_FromLong(i->what));
1306                 PyList_Append(list, tuple);
1307                 Py_DECREF(tuple);
1308         }
1309         
1310         return list;
1311 }
1312
1313 void eDVBServicePlay::setCutList(PyObject *list)
1314 {
1315         if (!PyList_Check(list))
1316                 return;
1317         int size = PyList_Size(list);
1318         int i;
1319         
1320         m_cue_entries.clear();
1321         
1322         for (i=0; i<size; ++i)
1323         {
1324                 PyObject *tuple = PyList_GetItem(list, i);
1325                 if (!PyTuple_Check(tuple))
1326                 {
1327                         eDebug("non-tuple in cutlist");
1328                         continue;
1329                 }
1330                 if (PyTuple_Size(tuple) != 2)
1331                 {
1332                         eDebug("cutlist entries need to be a 2-tuple");
1333                         continue;
1334                 }
1335                 PyObject *ppts = PyTuple_GetItem(tuple, 0), *ptype = PyTuple_GetItem(tuple, 1);
1336                 if (!(PyLong_Check(ppts) && PyInt_Check(ptype)))
1337                 {
1338                         eDebug("cutlist entries need to be (pts, type)-tuples (%d %d)", PyLong_Check(ppts), PyInt_Check(ptype));
1339                         continue;
1340                 }
1341                 pts_t pts = PyLong_AsLongLong(ppts);
1342                 int type = PyInt_AsLong(ptype);
1343                 m_cue_entries.insert(cueEntry(pts, type));
1344                 eDebug("adding %08llx, %d", pts, type);
1345         }
1346         m_cuesheet_changed = 1;
1347         
1348         cutlistToCuesheet();
1349         m_event((iPlayableService*)this, evCuesheetChanged);
1350 }
1351
1352 void eDVBServicePlay::setCutListEnable(int enable)
1353 {
1354         m_cutlist_enabled = enable;
1355         cutlistToCuesheet();
1356 }
1357
1358 void eDVBServicePlay::updateTimeshiftPids()
1359 {
1360         if (!m_record)
1361                 return;
1362         
1363         eDVBServicePMTHandler::program program;
1364         if (m_service_handler.getProgramInfo(program))
1365                 return;
1366         else
1367         {
1368                 std::set<int> pids_to_record;
1369                 pids_to_record.insert(0); // PAT
1370                 if (program.pmtPid != -1)
1371                         pids_to_record.insert(program.pmtPid); // PMT
1372
1373                 if (program.textPid != -1)
1374                         pids_to_record.insert(program.textPid); // Videotext
1375
1376                 for (std::vector<eDVBServicePMTHandler::videoStream>::const_iterator
1377                         i(program.videoStreams.begin()); 
1378                         i != program.videoStreams.end(); ++i)
1379                         pids_to_record.insert(i->pid);
1380
1381                 for (std::vector<eDVBServicePMTHandler::audioStream>::const_iterator
1382                         i(program.audioStreams.begin()); 
1383                         i != program.audioStreams.end(); ++i)
1384                                 pids_to_record.insert(i->pid);
1385
1386                 std::set<int> new_pids, obsolete_pids;
1387                 
1388                 std::set_difference(pids_to_record.begin(), pids_to_record.end(), 
1389                                 m_pids_active.begin(), m_pids_active.end(),
1390                                 std::inserter(new_pids, new_pids.begin()));
1391                 
1392                 std::set_difference(
1393                                 m_pids_active.begin(), m_pids_active.end(),
1394                                 pids_to_record.begin(), pids_to_record.end(), 
1395                                 std::inserter(new_pids, new_pids.begin())
1396                                 );
1397
1398                 for (std::set<int>::iterator i(new_pids.begin()); i != new_pids.end(); ++i)
1399                         m_record->addPID(*i);
1400
1401                 for (std::set<int>::iterator i(obsolete_pids.begin()); i != obsolete_pids.end(); ++i)
1402                         m_record->removePID(*i);
1403         }
1404 }
1405
1406 void eDVBServicePlay::switchToLive()
1407 {
1408         if (!m_timeshift_active)
1409                 return;
1410         
1411         m_decoder = 0;
1412         m_decode_demux = 0;
1413                 /* free the timeshift service handler, we need the resources */
1414         m_service_handler_timeshift.free();
1415         m_timeshift_active = 0;
1416         
1417         m_event((iPlayableService*)this, evSeekableStatusChanged);
1418         
1419         updateDecoder();
1420 }
1421
1422 void eDVBServicePlay::switchToTimeshift()
1423 {
1424         if (m_timeshift_active)
1425                 return;
1426         
1427         m_decode_demux = 0;
1428         m_decoder = 0;
1429         
1430         m_timeshift_active = 1;
1431
1432         m_event((iPlayableService*)this, evSeekableStatusChanged);
1433         
1434         eServiceReferenceDVB r = (eServiceReferenceDVB&)m_reference;
1435         r.path = m_timeshift_file;
1436         
1437         m_service_handler_timeshift.tune(r, 1, m_cue); /* use the decoder demux for everything */
1438 }
1439
1440 void eDVBServicePlay::updateDecoder()
1441 {
1442         int vpid = -1, apid = -1, apidtype = -1, pcrpid = -1, tpid = -1;
1443         eDVBServicePMTHandler &h = m_timeshift_active ? m_service_handler_timeshift : m_service_handler;
1444
1445         eDVBServicePMTHandler::program program;
1446         if (h.getProgramInfo(program))
1447                 eDebug("getting program info failed.");
1448         else
1449         {
1450                 eDebugNoNewLine("have %d video stream(s)", program.videoStreams.size());
1451                 if (!program.videoStreams.empty())
1452                 {
1453                         eDebugNoNewLine(" (");
1454                         for (std::vector<eDVBServicePMTHandler::videoStream>::const_iterator
1455                                 i(program.videoStreams.begin()); 
1456                                 i != program.videoStreams.end(); ++i)
1457                         {
1458                                 if (vpid == -1)
1459                                         vpid = i->pid;
1460                                 if (i != program.videoStreams.begin())
1461                                         eDebugNoNewLine(", ");
1462                                 eDebugNoNewLine("%04x", i->pid);
1463                         }
1464                         eDebugNoNewLine(")");
1465                 }
1466                 eDebugNoNewLine(", and %d audio stream(s)", program.audioStreams.size());
1467                 if (!program.audioStreams.empty())
1468                 {
1469                         eDebugNoNewLine(" (");
1470                         for (std::vector<eDVBServicePMTHandler::audioStream>::const_iterator
1471                                 i(program.audioStreams.begin()); 
1472                                 i != program.audioStreams.end(); ++i)
1473                         {
1474                                 if (apid == -1)
1475                                 {
1476                                         apid = i->pid;
1477                                         apidtype = i->type;
1478                                 }
1479                                 if (i != program.audioStreams.begin())
1480                                         eDebugNoNewLine(", ");
1481                                 eDebugNoNewLine("%04x", i->pid);
1482                         }
1483                         eDebugNoNewLine(")");
1484                 }
1485                 eDebugNoNewLine(", and the pcr pid is %04x", program.pcrPid);
1486                 pcrpid = program.pcrPid;
1487                 eDebug(", and the text pid is %04x", program.textPid);
1488                 tpid = program.textPid;
1489         }
1490
1491         if (!m_decoder)
1492         {
1493                 h.getDecodeDemux(m_decode_demux);
1494                 if (m_decode_demux)
1495                         m_decode_demux->getMPEGDecoder(m_decoder);
1496                 if (m_cue)
1497                         m_cue->setDecodingDemux(m_decode_demux, m_decoder);
1498         }
1499
1500         if (m_decoder)
1501         {
1502                 m_decoder->setVideoPID(vpid);
1503                 m_current_audio_stream = 0;
1504                 m_decoder->setAudioPID(apid, apidtype);
1505                 if (!(m_is_pvr || m_timeshift_active))
1506                         m_decoder->setSyncPCR(pcrpid);
1507                 else
1508                         m_decoder->setSyncPCR(-1);
1509                 m_decoder->setTextPID(tpid);
1510                 m_decoder->start();
1511 // how we can do this better?
1512 // update cache pid when the user changed the audio track or video track
1513 // TODO handling of difference audio types.. default audio types..
1514                                 
1515                 /* don't worry about non-existing services, nor pvr services */
1516                 if (m_dvb_service && !m_is_pvr)
1517                 {
1518                         if (apidtype == eDVBAudio::aMPEG)
1519                         {
1520                                 m_dvb_service->setCachePID(eDVBService::cAPID, apid);
1521                                 m_dvb_service->setCachePID(eDVBService::cAC3PID, -1);
1522                         }
1523                         else
1524                         {
1525                                 m_dvb_service->setCachePID(eDVBService::cAPID, -1);
1526                                 m_dvb_service->setCachePID(eDVBService::cAC3PID, apid);
1527                         }
1528                         m_dvb_service->setCachePID(eDVBService::cVPID, vpid);
1529                         m_dvb_service->setCachePID(eDVBService::cPCRPID, pcrpid);
1530                         m_dvb_service->setCachePID(eDVBService::cTPID, tpid);
1531                 }
1532         }
1533 }
1534
1535 void eDVBServicePlay::loadCuesheet()
1536 {
1537         std::string filename = m_reference.path + ".cuts";
1538         
1539         m_cue_entries.clear();
1540
1541         FILE *f = fopen(filename.c_str(), "rb");
1542
1543         if (f)
1544         {
1545                 eDebug("loading cuts..");
1546                 while (1)
1547                 {
1548                         unsigned long long where;
1549                         unsigned int what;
1550                         
1551                         if (!fread(&where, sizeof(where), 1, f))
1552                                 break;
1553                         if (!fread(&what, sizeof(what), 1, f))
1554                                 break;
1555                         
1556 #if BYTE_ORDER == LITTLE_ENDIAN
1557                         where = bswap_64(where);
1558 #endif
1559                         what = ntohl(what);
1560                         
1561                         if (what > 2)
1562                                 break;
1563                         
1564                         m_cue_entries.insert(cueEntry(where, what));
1565                 }
1566                 fclose(f);
1567                 eDebug("%d entries", m_cue_entries.size());
1568         } else
1569                 eDebug("cutfile not found!");
1570         
1571         m_cuesheet_changed = 0;
1572         cutlistToCuesheet();
1573         m_event((iPlayableService*)this, evCuesheetChanged);
1574 }
1575
1576 void eDVBServicePlay::saveCuesheet()
1577 {
1578         std::string filename = m_reference.path + ".cuts";
1579         
1580         FILE *f = fopen(filename.c_str(), "wb");
1581
1582         if (f)
1583         {
1584                 unsigned long long where;
1585                 int what;
1586
1587                 for (std::multiset<cueEntry>::iterator i(m_cue_entries.begin()); i != m_cue_entries.end(); ++i)
1588                 {
1589 #if BYTE_ORDER == BIG_ENDIAN
1590                         where = i->where;
1591 #else
1592                         where = bswap_64(i->where);
1593 #endif
1594                         what = htonl(i->what);
1595                         fwrite(&where, sizeof(where), 1, f);
1596                         fwrite(&what, sizeof(what), 1, f);
1597                         
1598                 }
1599                 fclose(f);
1600         }
1601         
1602         m_cuesheet_changed = 0;
1603 }
1604
1605 void eDVBServicePlay::cutlistToCuesheet()
1606 {
1607         if (!m_cue)
1608         {
1609                 eDebug("no cue sheet");
1610                 return;
1611         }       
1612         m_cue->clear();
1613         
1614         if (!m_cutlist_enabled)
1615         {
1616                 m_cue->commitSpans();
1617                 eDebug("cutlists where disabled");
1618                 return;
1619         }
1620
1621         pts_t in = 0, out = 0, length = 0;
1622         
1623         getLength(length);
1624                 
1625         std::multiset<cueEntry>::iterator i(m_cue_entries.begin());
1626         
1627         while (1)
1628         {
1629                 if (i == m_cue_entries.end())
1630                         out = length;
1631                 else {
1632                         if (i->what == 0) /* in */
1633                         {
1634                                 in = i++->where;
1635                                 continue;
1636                         } else if (i->what == 1) /* out */
1637                                 out = i++->where;
1638                         else /* mark */
1639                         {
1640                                 i++;
1641                                 continue;
1642                         }
1643                 }
1644                 
1645                 if (in != out)
1646                         m_cue->addSourceSpan(in, out);
1647                 
1648                 in = length;
1649                 
1650                 if (i == m_cue_entries.end())
1651                         break;
1652         }
1653         m_cue->commitSpans();
1654 }
1655
1656 DEFINE_REF(eDVBServicePlay)
1657
1658 eAutoInitPtr<eServiceFactoryDVB> init_eServiceFactoryDVB(eAutoInitNumbers::service+1, "eServiceFactoryDVB");