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