store a .eit file for each recoring this holds raw eit event informations
[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         
555         if (m_is_pvr)
556                 loadCuesheet();
557 }
558
559 eDVBServicePlay::~eDVBServicePlay()
560 {
561 }
562
563 void eDVBServicePlay::gotNewEvent()
564 {
565 #if 0
566                 // debug only
567         ePtr<eServiceEvent> m_event_now, m_event_next;
568         getEvent(m_event_now, 0);
569         getEvent(m_event_next, 1);
570
571         if (m_event_now)
572                 eDebug("now running: %s (%d seconds :)", m_event_now->m_event_name.c_str(), m_event_now->m_duration);
573         if (m_event_next)
574                 eDebug("next running: %s (%d seconds :)", m_event_next->m_event_name.c_str(), m_event_next->m_duration);
575 #endif
576         m_event((iPlayableService*)this, evUpdatedEventInfo);
577 }
578
579 void eDVBServicePlay::serviceEvent(int event)
580 {
581         switch (event)
582         {
583         case eDVBServicePMTHandler::eventTuned:
584         {
585                 ePtr<iDVBDemux> m_demux;
586                 if (!m_service_handler.getDataDemux(m_demux))
587                 {
588                         eServiceReferenceDVB &ref = (eServiceReferenceDVB&) m_reference;
589                         int sid = ref.getParentServiceID().get();
590                         if (!sid)
591                                 sid = ref.getServiceID().get();
592                         if ( ref.getParentTransportStreamID().get() &&
593                                 ref.getParentTransportStreamID() != ref.getTransportStreamID() )
594                                 m_event_handler.startOther(m_demux, sid);
595                         else
596                                 m_event_handler.start(m_demux, sid);
597                 }
598                 break;
599         }
600         case eDVBServicePMTHandler::eventTuneFailed:
601         {
602                 eDebug("DVB service failed to tune");
603                 m_event((iPlayableService*)this, evTuneFailed);
604                 break;
605         }
606         case eDVBServicePMTHandler::eventNewProgramInfo:
607         {
608                 eDebug("eventNewProgramInfo %d %d", m_timeshift_enabled, m_timeshift_active);
609                 if (m_timeshift_enabled)
610                         updateTimeshiftPids();
611                 if (!m_timeshift_active)
612                         updateDecoder();
613                 if (m_first_program_info && m_is_pvr)
614                 {
615                         m_first_program_info = 0;
616                         seekTo(0);
617                 }
618                 m_event((iPlayableService*)this, evUpdatedInfo);
619                 break;
620         }
621         case eDVBServicePMTHandler::eventEOF:
622                 m_event((iPlayableService*)this, evEOF);
623                 break;
624         case eDVBServicePMTHandler::eventSOF:
625                 m_event((iPlayableService*)this, evSOF);
626                 break;
627         }
628 }
629
630 void eDVBServicePlay::serviceEventTimeshift(int event)
631 {
632         switch (event)
633         {
634         case eDVBServicePMTHandler::eventNewProgramInfo:
635                 if (m_timeshift_active)
636                         updateDecoder();
637                 break;
638         case eDVBServicePMTHandler::eventEOF:
639                 switchToLive();
640                 break;
641         }
642 }
643
644 RESULT eDVBServicePlay::start()
645 {
646         int r;
647                 /* in pvr mode, we only want to use one demux. in tv mode, we're using 
648                    two (one for decoding, one for data source), as we must be prepared
649                    to start recording from the data demux. */
650         m_cue = new eCueSheet();
651         m_first_program_info = 1;
652         eServiceReferenceDVB &service = (eServiceReferenceDVB&)m_reference;
653         r = m_service_handler.tune(service, m_is_pvr, m_cue);
654         if (m_is_pvr)
655         {
656                 std::string filename = service.path;
657                 filename.erase(filename.length()-2, 2);
658                 filename+="eit";
659                 int fd = ::open( filename.c_str(), O_RDONLY );
660                 if ( fd > -1 )
661                 {
662                         __u8 buf[4096];
663                         int rd = ::read(fd, buf, 4096);
664                         ::close(fd);
665                         if ( rd > 12 /*EIT_LOOP_SIZE*/ )
666                         {
667                                 Event ev(buf);
668                                 ePtr<eServiceEvent> event = new eServiceEvent;
669                                 ePtr<eServiceEvent> empty;
670                                 event->parseFrom(&ev, (service.getTransportStreamID().get()<<16)|service.getOriginalNetworkID().get());
671                                 m_event_handler.inject(event, 0);
672                                 m_event_handler.inject(empty, 1);
673                                 eDebug("injected");
674                         }
675                 }
676         }
677         m_event(this, evStart);
678         m_event((iPlayableService*)this, evSeekableStatusChanged);
679         return 0;
680 }
681
682 RESULT eDVBServicePlay::stop()
683 {
684         stopTimeshift(); /* in case timeshift was enabled, remove buffer etc. */
685
686         m_service_handler_timeshift.free();
687         m_service_handler.free();
688         
689         if (m_is_pvr && m_cuesheet_changed)
690                 saveCuesheet();
691         
692         return 0;
693 }
694
695 RESULT eDVBServicePlay::connectEvent(const Slot2<void,iPlayableService*,int> &event, ePtr<eConnection> &connection)
696 {
697         connection = new eConnection((iPlayableService*)this, m_event.connect(event));
698         return 0;
699 }
700
701 RESULT eDVBServicePlay::pause(ePtr<iPauseableService> &ptr)
702 {
703                 /* note: we check for timeshift to be enabled,
704                    not neccessary active. if you pause when timeshift
705                    is not active, you should activate it when unpausing */
706         if ((!m_is_pvr) && (!m_timeshift_enabled))
707         {
708                 ptr = 0;
709                 return -1;
710         }
711
712         ptr = this;
713         return 0;
714 }
715
716 RESULT eDVBServicePlay::setSlowMotion(int ratio)
717 {
718         if (m_decoder)
719                 return m_decoder->setSlowMotion(ratio);
720         else
721                 return -1;
722 }
723
724 RESULT eDVBServicePlay::setFastForward(int ratio)
725 {
726         int skipmode, ffratio;
727         
728         if (ratio > 8)
729         {
730                 skipmode = ratio;
731                 ffratio = 1;
732         } else if (ratio > 0)
733         {
734                 skipmode = 0;
735                 ffratio = ratio;
736         } else if (!ratio)
737         {
738                 skipmode = 0;
739                 ffratio = 0;
740         } else // if (ratio < 0)
741         {
742                 skipmode = ratio;
743                 ffratio = 1;
744         }
745
746         if (m_skipmode != skipmode)
747         {
748                 eDebug("setting cue skipmode to %d", skipmode);
749                 if (m_cue)
750                         m_cue->setSkipmode(skipmode * 90000); /* convert to 90000 per second */
751         }
752         
753         m_skipmode = skipmode;
754         
755         if (!m_decoder)
756                 return -1;
757
758         return m_decoder->setFastForward(ffratio);
759 }
760     
761 RESULT eDVBServicePlay::seek(ePtr<iSeekableService> &ptr)
762 {
763         if (m_is_pvr || m_timeshift_enabled)
764         {
765                 ptr = this;
766                 return 0;
767         }
768         
769         ptr = 0;
770         return -1;
771 }
772
773         /* TODO: when timeshift is enabled but not active, this doesn't work. */
774 RESULT eDVBServicePlay::getLength(pts_t &len)
775 {
776         ePtr<iDVBPVRChannel> pvr_channel;
777         
778         if ((m_timeshift_enabled ? m_service_handler_timeshift : m_service_handler).getPVRChannel(pvr_channel))
779                 return -1;
780         
781         return pvr_channel->getLength(len);
782 }
783
784 RESULT eDVBServicePlay::pause()
785 {
786         if (!m_is_paused && m_decoder)
787         {
788                 m_is_paused = 1;
789                 return m_decoder->freeze(0);
790         } else
791                 return -1;
792 }
793
794 RESULT eDVBServicePlay::unpause()
795 {
796         if (m_is_paused && m_decoder)
797         {
798                 m_is_paused = 0;
799                 return m_decoder->unfreeze();
800         } else
801                 return -1;
802 }
803
804 RESULT eDVBServicePlay::seekTo(pts_t to)
805 {
806         eDebug("eDVBServicePlay::seekTo: jump %lld", to);
807         
808         if (!m_decode_demux)
809                 return -1;
810
811         ePtr<iDVBPVRChannel> pvr_channel;
812         
813         if ((m_timeshift_enabled ? m_service_handler_timeshift : m_service_handler).getPVRChannel(pvr_channel))
814                 return -1;
815         
816         if (!m_cue)
817                 return -1;
818         
819         m_cue->seekTo(0, to);
820         return 0;
821 }
822
823 RESULT eDVBServicePlay::seekRelative(int direction, pts_t to)
824 {
825         eDebug("eDVBServicePlay::seekRelative: jump %d, %lld", direction, to);
826         
827         if (!m_decode_demux)
828                 return -1;
829
830         ePtr<iDVBPVRChannel> pvr_channel;
831         
832         if ((m_timeshift_enabled ? m_service_handler_timeshift : m_service_handler).getPVRChannel(pvr_channel))
833                 return -1;
834         
835         to *= direction;
836         
837         if (!m_cue)
838                 return 0;
839         
840         m_cue->seekTo(1, to);
841         return 0;
842 }
843
844 RESULT eDVBServicePlay::getPlayPosition(pts_t &pos)
845 {
846         ePtr<iDVBPVRChannel> pvr_channel;
847         
848         if (!m_decode_demux)
849                 return -1;
850         
851         if ((m_timeshift_enabled ? m_service_handler_timeshift : m_service_handler).getPVRChannel(pvr_channel))
852                 return -1;
853         
854         int r = 0;
855
856                 /* if there is a decoder, use audio or video PTS */
857         if (m_decoder)
858         {
859                 r = m_decoder->getPTS(0, pos);
860                 if (r)
861                         return r;
862         }
863         
864                 /* fixup */
865         return pvr_channel->getCurrentPosition(m_decode_demux, pos, m_decoder ? 1 : 0);
866 }
867
868 RESULT eDVBServicePlay::setTrickmode(int trick)
869 {
870         if (m_decoder)
871                 m_decoder->setTrickmode(trick);
872         return 0;
873 }
874
875 RESULT eDVBServicePlay::isCurrentlySeekable()
876 {
877         return m_is_pvr || m_timeshift_active;
878 }
879
880 RESULT eDVBServicePlay::frontendStatusInfo(ePtr<iFrontendStatusInformation> &ptr)
881 {
882         ptr = this;
883         return 0;
884 }
885
886 RESULT eDVBServicePlay::info(ePtr<iServiceInformation> &ptr)
887 {
888         ptr = this;
889         return 0;
890 }
891
892 RESULT eDVBServicePlay::audioTracks(ePtr<iAudioTrackSelection> &ptr)
893 {
894         ptr = this;
895         return 0;
896 }
897
898 RESULT eDVBServicePlay::subServices(ePtr<iSubserviceList> &ptr)
899 {
900         ptr = this;
901         return 0;
902 }
903
904 RESULT eDVBServicePlay::timeshift(ePtr<iTimeshiftService> &ptr)
905 {
906         ptr = 0;
907         if (m_timeshift_enabled || !m_is_pvr)
908         {
909                 if (!m_timeshift_enabled)
910                 {
911                                 /* we need enough diskspace */
912                         struct statfs fs;
913                         if (statfs(TSPATH "/.", &fs) < 0)
914                         {
915                                 eDebug("statfs failed!");
916                                 return -2;
917                         }
918                 
919                         if (((off_t)fs.f_bavail) * ((off_t)fs.f_bsize) < 1024*1024*1024LL)
920                         {
921                                 eDebug("not enough diskspace for timeshift! (less than 1GB)");
922                                 return -3;
923                         }
924                 }
925                 ptr = this;
926                 return 0;
927         }
928         return -1;
929 }
930
931 RESULT eDVBServicePlay::cueSheet(ePtr<iCueSheet> &ptr)
932 {
933         if (m_is_pvr)
934         {
935                 ptr = this;
936                 return 0;
937         }
938         ptr = 0;
939         return -1;
940 }
941
942 RESULT eDVBServicePlay::getName(std::string &name)
943 {
944         if (m_is_pvr)
945         {
946                 ePtr<iStaticServiceInformation> i = new eStaticServiceDVBPVRInformation(m_reference);
947                 return i->getName(m_reference, name);
948         }
949         if (m_dvb_service)
950         {
951                 m_dvb_service->getName(m_reference, name);
952                 if (name.empty())
953                         name = "(...)";
954         }
955         else if (!m_reference.name.empty())
956                 eStaticServiceDVBInformation().getName(m_reference, name);
957         else
958                 name = "DVB service";
959         return 0;
960 }
961
962 RESULT eDVBServicePlay::getEvent(ePtr<eServiceEvent> &evt, int nownext)
963 {
964         return m_event_handler.getEvent(evt, nownext);
965 }
966
967 int eDVBServicePlay::getInfo(int w)
968 {
969         eDVBServicePMTHandler::program program;
970
971         if (m_service_handler.getProgramInfo(program))
972                 return -1;
973         
974         switch (w)
975         {
976         case sAspect:
977                 if (!program.videoStreams.empty() && program.videoStreams[0].component_tag != -1)
978                 {
979                         ePtr<eServiceEvent> evt;
980                         if (!m_event_handler.getEvent(evt, 0))
981                         {
982                                 ePtr<eComponentData> data;
983                                 if (!evt->getComponentData(data, program.videoStreams[0].component_tag))
984                                 {
985                                         if ( data->getStreamContent() == 1 )
986                                         {
987                                                 switch(data->getComponentType())
988                                                 {
989                                                         // SD
990                                                         case 1: // 4:3 SD PAL
991                                                         case 2:
992                                                         case 3: // 16:9 SD PAL
993                                                         case 4: // > 16:9 PAL
994                                                         case 5: // 4:3 SD NTSC
995                                                         case 6: 
996                                                         case 7: // 16:9 SD NTSC
997                                                         case 8: // > 16:9 NTSC
998
999                                                         // HD
1000                                                         case 9: // 4:3 HD PAL
1001                                                         case 0xA:
1002                                                         case 0xB: // 16:9 HD PAL
1003                                                         case 0xC: // > 16:9 HD PAL
1004                                                         case 0xD: // 4:3 HD NTSC
1005                                                         case 0xE:
1006                                                         case 0xF: // 16:9 HD NTSC
1007                                                         case 0x10: // > 16:9 HD PAL
1008                                                                 return data->getComponentType();
1009                                                 }
1010                                         }
1011                                 }
1012                         }
1013                 }
1014                 return -1;
1015         case sIsCrypted: return program.isCrypted;
1016         case sVideoPID: if (program.videoStreams.empty()) return -1; return program.videoStreams[0].pid;
1017         case sAudioPID: if (program.audioStreams.empty()) return -1; return program.audioStreams[m_current_audio_stream].pid;
1018         case sPCRPID: return program.pcrPid;
1019         case sPMTPID: return program.pmtPid;
1020         case sTXTPID: return program.textPid;
1021         case sSID: return ((const eServiceReferenceDVB&)m_reference).getServiceID().get();
1022         case sONID: return ((const eServiceReferenceDVB&)m_reference).getOriginalNetworkID().get();
1023         case sTSID: return ((const eServiceReferenceDVB&)m_reference).getTransportStreamID().get();
1024         case sNamespace: return ((const eServiceReferenceDVB&)m_reference).getDVBNamespace().get();
1025         case sProvider: if (!m_dvb_service) return -1; return -2;
1026         default:
1027                 return -1;
1028         }
1029 }
1030
1031 std::string eDVBServicePlay::getInfoString(int w)
1032 {       
1033         switch (w)
1034         {
1035         case sProvider:
1036                 if (!m_dvb_service) return "";
1037                 return m_dvb_service->m_provider_name;
1038         default:
1039                 return "";
1040         }
1041 }
1042
1043 int eDVBServicePlay::getNumberOfTracks()
1044 {
1045         eDVBServicePMTHandler::program program;
1046         if (m_service_handler.getProgramInfo(program))
1047                 return 0;
1048         return program.audioStreams.size();
1049 }
1050
1051 RESULT eDVBServicePlay::selectTrack(unsigned int i)
1052 {
1053         int ret = selectAudioStream(i);
1054
1055         if (m_decoder->start())
1056                 return -5;
1057
1058         return ret;
1059 }
1060
1061 RESULT eDVBServicePlay::getTrackInfo(struct iAudioTrackInfo &info, unsigned int i)
1062 {
1063         eDVBServicePMTHandler::program program;
1064
1065         if (m_service_handler.getProgramInfo(program))
1066                 return -1;
1067         
1068         if (i >= program.audioStreams.size())
1069                 return -2;
1070         
1071         if (program.audioStreams[i].type == eDVBServicePMTHandler::audioStream::atMPEG)
1072                 info.m_description = "MPEG";
1073         else if (program.audioStreams[i].type == eDVBServicePMTHandler::audioStream::atAC3)
1074                 info.m_description = "AC3";
1075         else  if (program.audioStreams[i].type == eDVBServicePMTHandler::audioStream::atDTS)
1076                 info.m_description = "DTS";
1077         else
1078                 info.m_description = "???";
1079
1080         if (program.audioStreams[i].component_tag != -1)
1081         {
1082                 ePtr<eServiceEvent> evt;
1083                 if (!m_event_handler.getEvent(evt, 0))
1084                 {
1085                         ePtr<eComponentData> data;
1086                         if (!evt->getComponentData(data, program.audioStreams[i].component_tag))
1087                                 info.m_language = data->getText();
1088                 }
1089         }
1090
1091         if (info.m_language.empty())
1092                 info.m_language = program.audioStreams[i].language_code;
1093         
1094         return 0;
1095 }
1096
1097 int eDVBServicePlay::selectAudioStream(int i)
1098 {
1099         eDVBServicePMTHandler::program program;
1100
1101         if (m_service_handler.getProgramInfo(program))
1102                 return -1;
1103         
1104         if ((unsigned int)i >= program.audioStreams.size())
1105                 return -2;
1106         
1107         if (!m_decoder)
1108                 return -3;
1109         
1110         if (m_decoder->setAudioPID(program.audioStreams[i].pid, program.audioStreams[i].type))
1111                 return -4;
1112
1113         if (m_dvb_service && !m_is_pvr)
1114         {
1115                 if (program.audioStreams[i].type == eDVBAudio::aMPEG)
1116                 {
1117                         m_dvb_service->setCachePID(eDVBService::cAPID, program.audioStreams[i].pid);
1118                         m_dvb_service->setCachePID(eDVBService::cAC3PID, -1);
1119                 }       else
1120                 {
1121                         m_dvb_service->setCachePID(eDVBService::cAPID, -1);
1122                         m_dvb_service->setCachePID(eDVBService::cAC3PID, program.audioStreams[i].pid);
1123                 }
1124         }
1125
1126         m_current_audio_stream = i;
1127
1128         return 0;
1129 }
1130
1131 int eDVBServicePlay::getFrontendInfo(int w)
1132 {
1133         if (m_is_pvr)
1134                 return 0;
1135         eUsePtr<iDVBChannel> channel;
1136         if(m_service_handler.getChannel(channel))
1137                 return 0;
1138         ePtr<iDVBFrontend> fe;
1139         if(channel->getFrontend(fe))
1140                 return 0;
1141         return fe->readFrontendData(w);
1142 }
1143
1144 int eDVBServicePlay::getNumberOfSubservices()
1145 {
1146         ePtr<eServiceEvent> evt;
1147         if (!m_event_handler.getEvent(evt, 0))
1148                 return evt->getNumOfLinkageServices();
1149         return 0;
1150 }
1151
1152 RESULT eDVBServicePlay::getSubservice(eServiceReference &sub, unsigned int n)
1153 {
1154         ePtr<eServiceEvent> evt;
1155         if (!m_event_handler.getEvent(evt, 0))
1156         {
1157                 if (!evt->getLinkageService(sub, m_reference, n))
1158                         return 0;
1159         }
1160         sub.type=eServiceReference::idInvalid;
1161         return -1;
1162 }
1163
1164 RESULT eDVBServicePlay::startTimeshift()
1165 {
1166         ePtr<iDVBDemux> demux;
1167         
1168         eDebug("Start timeshift!");
1169         
1170         if (m_timeshift_enabled)
1171                 return -1;
1172         
1173                 /* start recording with the data demux. */
1174         if (m_service_handler.getDataDemux(demux))
1175                 return -2;
1176
1177         demux->createTSRecorder(m_record);
1178         if (!m_record)
1179                 return -3;
1180
1181         char templ[]=TSPATH "/timeshift.XXXXXX";
1182         m_timeshift_fd = mkstemp(templ);
1183         m_timeshift_file = templ;
1184         
1185         eDebug("recording to %s", templ);
1186         
1187         if (m_timeshift_fd < 0)
1188         {
1189                 m_record = 0;
1190                 return -4;
1191         }
1192                 
1193         m_record->setTargetFD(m_timeshift_fd);
1194
1195         m_timeshift_enabled = 1;
1196         
1197         updateTimeshiftPids();
1198         m_record->start();
1199
1200         return 0;
1201 }
1202
1203 RESULT eDVBServicePlay::stopTimeshift()
1204 {
1205         if (!m_timeshift_enabled)
1206                 return -1;
1207         
1208         switchToLive();
1209         
1210         m_timeshift_enabled = 0;
1211         
1212         m_record->stop();
1213         m_record = 0;
1214         
1215         close(m_timeshift_fd);
1216         eDebug("remove timeshift file");
1217         remove(m_timeshift_file.c_str());
1218         
1219         return 0;
1220 }
1221
1222 int eDVBServicePlay::isTimeshiftActive()
1223 {
1224         return m_timeshift_enabled && m_timeshift_active;
1225 }
1226
1227 RESULT eDVBServicePlay::activateTimeshift()
1228 {
1229         if (!m_timeshift_enabled)
1230                 return -1;
1231         
1232         if (!m_timeshift_active)
1233         {
1234                 switchToTimeshift();
1235                 return 0;
1236         }
1237         
1238         return -2;
1239 }
1240
1241 PyObject *eDVBServicePlay::getCutList()
1242 {
1243         PyObject *list = PyList_New(0);
1244         
1245         for (std::multiset<struct cueEntry>::iterator i(m_cue_entries.begin()); i != m_cue_entries.end(); ++i)
1246         {
1247                 PyObject *tuple = PyTuple_New(2);
1248                 PyTuple_SetItem(tuple, 0, PyLong_FromLongLong(i->where));
1249                 PyTuple_SetItem(tuple, 1, PyInt_FromLong(i->what));
1250                 PyList_Append(list, tuple);
1251                 Py_DECREF(tuple);
1252         }
1253         
1254         return list;
1255 }
1256
1257 void eDVBServicePlay::setCutList(PyObject *list)
1258 {
1259         if (!PyList_Check(list))
1260                 return;
1261         int size = PyList_Size(list);
1262         int i;
1263         
1264         m_cue_entries.clear();
1265         
1266         for (i=0; i<size; ++i)
1267         {
1268                 PyObject *tuple = PyList_GetItem(list, i);
1269                 if (!PyTuple_Check(tuple))
1270                 {
1271                         eDebug("non-tuple in cutlist");
1272                         continue;
1273                 }
1274                 if (PyTuple_Size(tuple) != 2)
1275                 {
1276                         eDebug("cutlist entries need to be a 2-tuple");
1277                         continue;
1278                 }
1279                 PyObject *ppts = PyTuple_GetItem(tuple, 0), *ptype = PyTuple_GetItem(tuple, 1);
1280                 if (!(PyLong_Check(ppts) && PyInt_Check(ptype)))
1281                 {
1282                         eDebug("cutlist entries need to be (pts, type)-tuples (%d %d)", PyLong_Check(ppts), PyInt_Check(ptype));
1283                         continue;
1284                 }
1285                 pts_t pts = PyLong_AsLongLong(ppts);
1286                 int type = PyInt_AsLong(ptype);
1287                 m_cue_entries.insert(cueEntry(pts, type));
1288                 eDebug("adding %08llx, %d", pts, type);
1289         }
1290         m_cuesheet_changed = 1;
1291         
1292         m_event((iPlayableService*)this, evCuesheetChanged);
1293 }
1294
1295 void eDVBServicePlay::updateTimeshiftPids()
1296 {
1297         if (!m_record)
1298                 return;
1299         
1300         eDVBServicePMTHandler::program program;
1301         if (m_service_handler.getProgramInfo(program))
1302                 return;
1303         else
1304         {
1305                 std::set<int> pids_to_record;
1306                 pids_to_record.insert(0); // PAT
1307                 if (program.pmtPid != -1)
1308                         pids_to_record.insert(program.pmtPid); // PMT
1309
1310                 if (program.textPid != -1)
1311                         pids_to_record.insert(program.textPid); // Videotext
1312
1313                 for (std::vector<eDVBServicePMTHandler::videoStream>::const_iterator
1314                         i(program.videoStreams.begin()); 
1315                         i != program.videoStreams.end(); ++i)
1316                         pids_to_record.insert(i->pid);
1317
1318                 for (std::vector<eDVBServicePMTHandler::audioStream>::const_iterator
1319                         i(program.audioStreams.begin()); 
1320                         i != program.audioStreams.end(); ++i)
1321                                 pids_to_record.insert(i->pid);
1322
1323                 std::set<int> new_pids, obsolete_pids;
1324                 
1325                 std::set_difference(pids_to_record.begin(), pids_to_record.end(), 
1326                                 m_pids_active.begin(), m_pids_active.end(),
1327                                 std::inserter(new_pids, new_pids.begin()));
1328                 
1329                 std::set_difference(
1330                                 m_pids_active.begin(), m_pids_active.end(),
1331                                 pids_to_record.begin(), pids_to_record.end(), 
1332                                 std::inserter(new_pids, new_pids.begin())
1333                                 );
1334
1335                 for (std::set<int>::iterator i(new_pids.begin()); i != new_pids.end(); ++i)
1336                         m_record->addPID(*i);
1337
1338                 for (std::set<int>::iterator i(obsolete_pids.begin()); i != obsolete_pids.end(); ++i)
1339                         m_record->removePID(*i);
1340         }
1341 }
1342
1343 void eDVBServicePlay::switchToLive()
1344 {
1345         if (!m_timeshift_active)
1346                 return;
1347         
1348         m_decoder = 0;
1349         m_decode_demux = 0;
1350                 /* free the timeshift service handler, we need the resources */
1351         m_service_handler_timeshift.free();
1352         m_timeshift_active = 0;
1353         
1354         m_event((iPlayableService*)this, evSeekableStatusChanged);
1355         
1356         updateDecoder();
1357 }
1358
1359 void eDVBServicePlay::switchToTimeshift()
1360 {
1361         if (m_timeshift_active)
1362                 return;
1363         
1364         m_decode_demux = 0;
1365         m_decoder = 0;
1366         
1367         m_timeshift_active = 1;
1368
1369         m_event((iPlayableService*)this, evSeekableStatusChanged);
1370         
1371         eServiceReferenceDVB r = (eServiceReferenceDVB&)m_reference;
1372         r.path = m_timeshift_file;
1373         
1374         m_service_handler_timeshift.tune(r, 1, m_cue); /* use the decoder demux for everything */
1375 }
1376
1377 void eDVBServicePlay::updateDecoder()
1378 {
1379         int vpid = -1, apid = -1, apidtype = -1, pcrpid = -1, tpid = -1;
1380         eDVBServicePMTHandler &h = m_timeshift_active ? m_service_handler_timeshift : m_service_handler;
1381
1382         eDVBServicePMTHandler::program program;
1383         if (h.getProgramInfo(program))
1384                 eDebug("getting program info failed.");
1385         else
1386         {
1387                 eDebugNoNewLine("have %d video stream(s)", program.videoStreams.size());
1388                 if (!program.videoStreams.empty())
1389                 {
1390                         eDebugNoNewLine(" (");
1391                         for (std::vector<eDVBServicePMTHandler::videoStream>::const_iterator
1392                                 i(program.videoStreams.begin()); 
1393                                 i != program.videoStreams.end(); ++i)
1394                         {
1395                                 if (vpid == -1)
1396                                         vpid = i->pid;
1397                                 if (i != program.videoStreams.begin())
1398                                         eDebugNoNewLine(", ");
1399                                 eDebugNoNewLine("%04x", i->pid);
1400                         }
1401                         eDebugNoNewLine(")");
1402                 }
1403                 eDebugNoNewLine(", and %d audio stream(s)", program.audioStreams.size());
1404                 if (!program.audioStreams.empty())
1405                 {
1406                         eDebugNoNewLine(" (");
1407                         for (std::vector<eDVBServicePMTHandler::audioStream>::const_iterator
1408                                 i(program.audioStreams.begin()); 
1409                                 i != program.audioStreams.end(); ++i)
1410                         {
1411                                 if (apid == -1)
1412                                 {
1413                                         apid = i->pid;
1414                                         apidtype = i->type;
1415                                 }
1416                                 if (i != program.audioStreams.begin())
1417                                         eDebugNoNewLine(", ");
1418                                 eDebugNoNewLine("%04x", i->pid);
1419                         }
1420                         eDebugNoNewLine(")");
1421                 }
1422                 eDebugNoNewLine(", and the pcr pid is %04x", program.pcrPid);
1423                 pcrpid = program.pcrPid;
1424                 eDebug(", and the text pid is %04x", program.textPid);
1425                 tpid = program.textPid;
1426         }
1427
1428         if (!m_decoder)
1429         {
1430                 h.getDecodeDemux(m_decode_demux);
1431                 if (m_decode_demux)
1432                         m_decode_demux->getMPEGDecoder(m_decoder);
1433                 if (m_cue)
1434                         m_cue->setDecodingDemux(m_decode_demux, m_decoder);
1435         }
1436
1437         if (m_decoder)
1438         {
1439                 m_decoder->setVideoPID(vpid);
1440                 m_current_audio_stream = 0;
1441                 m_decoder->setAudioPID(apid, apidtype);
1442                 if (!(m_is_pvr || m_timeshift_active))
1443                         m_decoder->setSyncPCR(pcrpid);
1444                 else
1445                         m_decoder->setSyncPCR(-1);
1446                 m_decoder->setTextPID(tpid);
1447                 m_decoder->start();
1448 // how we can do this better?
1449 // update cache pid when the user changed the audio track or video track
1450 // TODO handling of difference audio types.. default audio types..
1451                                 
1452                 /* don't worry about non-existing services, nor pvr services */
1453                 if (m_dvb_service && !m_is_pvr)
1454                 {
1455                         if (apidtype == eDVBAudio::aMPEG)
1456                         {
1457                                 m_dvb_service->setCachePID(eDVBService::cAPID, apid);
1458                                 m_dvb_service->setCachePID(eDVBService::cAC3PID, -1);
1459                         }
1460                         else
1461                         {
1462                                 m_dvb_service->setCachePID(eDVBService::cAPID, -1);
1463                                 m_dvb_service->setCachePID(eDVBService::cAC3PID, apid);
1464                         }
1465                         m_dvb_service->setCachePID(eDVBService::cVPID, vpid);
1466                         m_dvb_service->setCachePID(eDVBService::cPCRPID, pcrpid);
1467                         m_dvb_service->setCachePID(eDVBService::cTPID, tpid);
1468                 }
1469         }
1470 }
1471
1472 void eDVBServicePlay::loadCuesheet()
1473 {
1474         std::string filename = m_reference.path + ".cuts";
1475         
1476         m_cue_entries.clear();
1477
1478         FILE *f = fopen(filename.c_str(), "rb");
1479
1480         if (f)
1481         {
1482                 eDebug("loading cuts..");
1483                 while (1)
1484                 {
1485                         unsigned long long where;
1486                         unsigned int what;
1487                         
1488                         if (!fread(&where, sizeof(where), 1, f))
1489                                 break;
1490                         if (!fread(&what, sizeof(what), 1, f))
1491                                 break;
1492                         
1493 #if BYTE_ORDER == LITTLE_ENDIAN
1494                         where = bswap_64(where);
1495 #endif
1496                         what = ntohl(what);
1497                         
1498                         if (what > 2)
1499                                 break;
1500                         
1501                         m_cue_entries.insert(cueEntry(where, what));
1502                 }
1503                 fclose(f);
1504                 eDebug("%d entries", m_cue_entries.size());
1505         } else
1506                 eDebug("cutfile not found!");
1507         
1508         m_cuesheet_changed = 0;
1509         m_event((iPlayableService*)this, evCuesheetChanged);
1510 }
1511
1512 void eDVBServicePlay::saveCuesheet()
1513 {
1514         std::string filename = m_reference.path + ".cuts";
1515         
1516         FILE *f = fopen(filename.c_str(), "wb");
1517
1518         if (f)
1519         {
1520                 unsigned long long where;
1521                 int what;
1522
1523                 for (std::multiset<cueEntry>::iterator i(m_cue_entries.begin()); i != m_cue_entries.end(); ++i)
1524                 {
1525 #if BYTE_ORDER == BIG_ENDIAN
1526                         where = i->where;
1527 #else
1528                         where = bswap_64(i->where);
1529 #endif
1530                         what = htonl(i->what);
1531                         fwrite(&where, sizeof(where), 1, f);
1532                         fwrite(&what, sizeof(what), 1, f);
1533                         
1534                 }
1535                 fclose(f);
1536         }
1537         
1538         m_cuesheet_changed = 0;
1539 }
1540
1541 DEFINE_REF(eDVBServicePlay)
1542
1543 eAutoInitPtr<eServiceFactoryDVB> init_eServiceFactoryDVB(eAutoInitNumbers::service+1, "eServiceFactoryDVB");