patch by Dr.Best - allow using filesize of movie in converter
[vuplus_dvbapp] / 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/estring.h>
7 #include <lib/base/init_num.h>
8 #include <lib/base/init.h>
9 #include <lib/dvb/dvb.h>
10 #include <lib/dvb/db.h>
11 #include <lib/dvb/decoder.h>
12
13 #include <lib/components/file_eraser.h>
14 #include <lib/service/servicedvbrecord.h>
15 #include <lib/service/event.h>
16 #include <lib/dvb/metaparser.h>
17 #include <lib/dvb/tstools.h>
18 #include <lib/python/python.h>
19 #include <lib/base/nconfig.h> // access to python config
20
21                 /* for subtitles */
22 #include <lib/gui/esubtitle.h>
23
24 #include <sys/vfs.h>
25 #include <sys/stat.h>
26
27 #include <byteswap.h>
28 #include <netinet/in.h>
29
30 #ifndef BYTE_ORDER
31 #error no byte order defined!
32 #endif
33
34 class eStaticServiceDVBInformation: public iStaticServiceInformation
35 {
36         DECLARE_REF(eStaticServiceDVBInformation);
37 public:
38         RESULT getName(const eServiceReference &ref, std::string &name);
39         int getLength(const eServiceReference &ref);
40         int isPlayable(const eServiceReference &ref, const eServiceReference &ignore);
41         PyObject *getInfoObject(const eServiceReference &ref, int);
42 };
43
44 DEFINE_REF(eStaticServiceDVBInformation);
45
46 RESULT eStaticServiceDVBInformation::getName(const eServiceReference &ref, std::string &name)
47 {
48         eServiceReferenceDVB &service = (eServiceReferenceDVB&)ref;
49         if ( !ref.name.empty() )
50         {
51                 if (service.getParentTransportStreamID().get()) // linkage subservice
52                 {
53                         ePtr<iServiceHandler> service_center;
54                         if (!eServiceCenter::getInstance(service_center))
55                         {
56                                 eServiceReferenceDVB parent = service;
57                                 parent.setTransportStreamID( service.getParentTransportStreamID() );
58                                 parent.setServiceID( service.getParentServiceID() );
59                                 parent.setParentTransportStreamID(eTransportStreamID(0));
60                                 parent.setParentServiceID(eServiceID(0));
61                                 parent.name="";
62                                 ePtr<iStaticServiceInformation> service_info;
63                                 if (!service_center->info(parent, service_info))
64                                 {
65                                         if (!service_info->getName(parent, name))
66                                                 name=buildShortName(name) + " - ";
67                                 }
68                         }
69                 }
70                 else
71                         name="";
72                 name += ref.name;
73                 return 0;
74         }
75         else
76                 return -1;
77 }
78
79 int eStaticServiceDVBInformation::getLength(const eServiceReference &ref)
80 {
81         return -1;
82 }
83
84 int eStaticServiceDVBInformation::isPlayable(const eServiceReference &ref, const eServiceReference &ignore)
85 {
86         ePtr<eDVBResourceManager> res_mgr;
87         if ( eDVBResourceManager::getInstance( res_mgr ) )
88                 eDebug("isPlayable... no res manager!!");
89         else
90         {
91                 eDVBChannelID chid, chid_ignore;
92                 ((const eServiceReferenceDVB&)ref).getChannelID(chid);
93                 ((const eServiceReferenceDVB&)ignore).getChannelID(chid_ignore);
94                 return res_mgr->canAllocateChannel(chid, chid_ignore);
95         }
96         return false;
97 }
98
99 extern void PutToDict(ePyObject &dict, const char*key, long value);  // defined in dvb/frontend.cpp
100 extern void PutToDict(ePyObject &dict, const char*key, ePyObject item); // defined in dvb/frontend.cpp
101 extern void PutToDict(ePyObject &dict, const char*key, const char *value); // defined in dvb/frontend.cpp
102
103 void PutSatelliteDataToDict(ePyObject &dict, eDVBFrontendParametersSatellite &feparm)
104 {
105         PutToDict(dict, "tuner_type", "DVB-S");
106         PutToDict(dict, "frequency", feparm.frequency);
107         PutToDict(dict, "symbol_rate", feparm.symbol_rate);
108         PutToDict(dict, "orbital_position", feparm.orbital_position);
109         PutToDict(dict, "inversion", feparm.inversion);
110         PutToDict(dict, "fec_inner", feparm.fec);
111         PutToDict(dict, "modulation", feparm.modulation);
112         PutToDict(dict, "polarization", feparm.polarisation);
113         if (feparm.system == eDVBFrontendParametersSatellite::System_DVB_S2)
114         {
115                 PutToDict(dict, "rolloff", feparm.rolloff);
116                 PutToDict(dict, "pilot", feparm.pilot);
117         }
118         PutToDict(dict, "system", feparm.system);
119 }
120
121 void PutTerrestrialDataToDict(ePyObject &dict, eDVBFrontendParametersTerrestrial &feparm)
122 {
123         PutToDict(dict, "tuner_type", "DVB-T");
124         PutToDict(dict, "frequency", feparm.frequency);
125         PutToDict(dict, "bandwidth", feparm.bandwidth);
126         PutToDict(dict, "code_rate_lp", feparm.code_rate_LP);
127         PutToDict(dict, "code_rate_hp", feparm.code_rate_HP);
128         PutToDict(dict, "constellation", feparm.modulation);
129         PutToDict(dict, "transmission_mode", feparm.transmission_mode);
130         PutToDict(dict, "guard_interval", feparm.guard_interval);
131         PutToDict(dict, "hierarchy_information", feparm.hierarchy);
132         PutToDict(dict, "inversion", feparm.inversion);
133 }
134
135 void PutCableDataToDict(ePyObject &dict, eDVBFrontendParametersCable &feparm)
136 {
137         PutToDict(dict, "tuner_type", "DVB-C");
138         PutToDict(dict, "frequency", feparm.frequency);
139         PutToDict(dict, "symbol_rate", feparm.symbol_rate);
140         PutToDict(dict, "modulation", feparm.modulation);
141         PutToDict(dict, "inversion", feparm.inversion);
142         PutToDict(dict, "fec_inner", feparm.fec_inner);
143 }
144
145 PyObject *eStaticServiceDVBInformation::getInfoObject(const eServiceReference &r, int what)
146 {
147         if (r.type == eServiceReference::idDVB)
148         {
149                 const eServiceReferenceDVB &ref = (const eServiceReferenceDVB&)r;
150                 switch(what)
151                 {
152                         case iServiceInformation::sTransponderData:
153                         {
154                                 ePtr<eDVBResourceManager> res;
155                                 if (!eDVBResourceManager::getInstance(res))
156                                 {
157                                         ePtr<iDVBChannelList> db;
158                                         if (!res->getChannelList(db))
159                                         {
160                                                 eDVBChannelID chid;
161                                                 ref.getChannelID(chid);
162                                                 ePtr<iDVBFrontendParameters> feparm;
163                                                 if (!db->getChannelFrontendData(chid, feparm))
164                                                 {
165                                                         int system;
166                                                         if (!feparm->getSystem(system))
167                                                         {
168                                                                 ePyObject dict = PyDict_New();
169                                                                 switch(system)
170                                                                 {
171                                                                         case iDVBFrontend::feSatellite:
172                                                                         {
173                                                                                 eDVBFrontendParametersSatellite s;
174                                                                                 feparm->getDVBS(s);
175                                                                                 PutSatelliteDataToDict(dict, s);
176                                                                                 break;
177                                                                         }
178                                                                         case iDVBFrontend::feTerrestrial:
179                                                                         {
180                                                                                 eDVBFrontendParametersTerrestrial t;
181                                                                                 feparm->getDVBT(t);
182                                                                                 PutTerrestrialDataToDict(dict, t);
183                                                                                 break;
184                                                                         }
185                                                                         case iDVBFrontend::feCable:
186                                                                         {
187                                                                                 eDVBFrontendParametersCable c;
188                                                                                 feparm->getDVBC(c);
189                                                                                 PutCableDataToDict(dict, c);
190                                                                                 break;
191                                                                         }
192                                                                         default:
193                                                                                 eDebug("unknown frontend type %d", system);
194                                                                                 Py_DECREF(dict);
195                                                                                 break;
196                                                                 }
197                                                                 return dict;
198                                                         }
199                                                 }
200                                         }
201                                 }
202                         }
203                 }
204         }
205         Py_RETURN_NONE;
206 }
207
208 DEFINE_REF(eStaticServiceDVBBouquetInformation);
209
210 RESULT eStaticServiceDVBBouquetInformation::getName(const eServiceReference &ref, std::string &name)
211 {
212         ePtr<iDVBChannelList> db;
213         ePtr<eDVBResourceManager> res;
214
215         int err;
216         if ((err = eDVBResourceManager::getInstance(res)) != 0)
217         {
218                 eDebug("eStaticServiceDVBBouquetInformation::getName failed.. no resource manager!");
219                 return err;
220         }
221         if ((err = res->getChannelList(db)) != 0)
222         {
223                 eDebug("eStaticServiceDVBBouquetInformation::getName failed.. no channel list!");
224                 return err;
225         }
226
227         eBouquet *bouquet=0;
228         if ((err = db->getBouquet(ref, bouquet)) != 0)
229         {
230                 eDebug("eStaticServiceDVBBouquetInformation::getName failed.. getBouquet failed!");
231                 return -1;
232         }
233
234         if ( bouquet && bouquet->m_bouquet_name.length() )
235         {
236                 name = bouquet->m_bouquet_name;
237                 return 0;
238         }
239         else
240                 return -1;
241 }
242
243 int eStaticServiceDVBBouquetInformation::isPlayable(const eServiceReference &ref, const eServiceReference &ignore, bool simulate)
244 {
245         if (ref.flags & eServiceReference::isGroup)
246         {
247                 ePtr<iDVBChannelList> db;
248                 ePtr<eDVBResourceManager> res;
249
250                 if (eDVBResourceManager::getInstance(res))
251                 {
252                         eDebug("eStaticServiceDVBBouquetInformation::isPlayable failed.. no resource manager!");
253                         return 0;
254                 }
255
256                 if (res->getChannelList(db))
257                 {
258                         eDebug("eStaticServiceDVBBouquetInformation::isPlayable failed.. no channel list!");
259                         return 0;
260                 }
261
262                 eBouquet *bouquet=0;
263                 if (db->getBouquet(ref, bouquet))
264                 {
265                         eDebug("eStaticServiceDVBBouquetInformation::isPlayable failed.. getBouquet failed!");
266                         return 0;
267                 }
268
269                 int prio_order = eDVBFrontend::getTypePriorityOrder();
270                 int cur=0;
271                 eDVBChannelID chid, chid_ignore;
272                 ((const eServiceReferenceDVB&)ignore).getChannelID(chid_ignore);
273                 for (std::list<eServiceReference>::iterator it(bouquet->m_services.begin()); it != bouquet->m_services.end(); ++it)
274                 {
275                         static unsigned char prio_map[6][3] = {
276                                 { 3, 2, 1 }, // -S -C -T
277                                 { 3, 1, 2 }, // -S -T -C
278                                 { 2, 3, 1 }, // -C -S -T
279                                 { 1, 3, 2 }, // -C -T -S
280                                 { 1, 2, 3 }, // -T -C -S
281                                 { 2, 1, 3 }  // -T -S -C
282                         };
283                         ((const eServiceReferenceDVB&)*it).getChannelID(chid);
284                         int tmp=res->canAllocateChannel(chid, chid_ignore, simulate);
285                         switch(tmp)
286                         {
287                                 case 0:
288                                         break;
289                                 case 30000: // cached DVB-T channel
290                                 case 1: // DVB-T frontend
291                                         tmp = prio_map[prio_order][2];
292                                         break;
293                                 case 40000: // cached DVB-C channel
294                                 case 2:
295                                         tmp = prio_map[prio_order][1];
296                                         break;
297                                 default: // DVB-S
298                                         tmp = prio_map[prio_order][0];
299                                         break;
300                         }
301                         if (tmp > cur)
302                         {
303                                 m_playable_service = *it;
304                                 cur = tmp;
305                         }
306                 }
307                 if (cur)
308                         return cur;
309         }
310         m_playable_service = eServiceReference();
311         return 0;
312 }
313
314 int eStaticServiceDVBBouquetInformation::getLength(const eServiceReference &ref)
315 {
316         return -1;
317 }
318
319 #include <lib/dvb/epgcache.h>
320
321 RESULT eStaticServiceDVBBouquetInformation::getEvent(const eServiceReference &ref, ePtr<eServiceEvent> &ptr, time_t start_time)
322 {
323         return eEPGCache::getInstance()->lookupEventTime(ref, start_time, ptr);
324 }
325
326 class eStaticServiceDVBPVRInformation: public iStaticServiceInformation
327 {
328         DECLARE_REF(eStaticServiceDVBPVRInformation);
329         eServiceReference m_ref;
330         eDVBMetaParser m_parser;
331 public:
332         eStaticServiceDVBPVRInformation(const eServiceReference &ref);
333         RESULT getName(const eServiceReference &ref, std::string &name);
334         int getLength(const eServiceReference &ref);
335         RESULT getEvent(const eServiceReference &ref, ePtr<eServiceEvent> &SWIG_OUTPUT, time_t start_time);
336         int isPlayable(const eServiceReference &ref, const eServiceReference &ignore) { return 1; }
337         int getInfo(const eServiceReference &ref, int w);
338         std::string getInfoString(const eServiceReference &ref,int w);
339 };
340
341 DEFINE_REF(eStaticServiceDVBPVRInformation);
342
343 eStaticServiceDVBPVRInformation::eStaticServiceDVBPVRInformation(const eServiceReference &ref)
344 {
345         m_ref = ref;
346         m_parser.parseFile(ref.path);
347 }
348
349 RESULT eStaticServiceDVBPVRInformation::getName(const eServiceReference &ref, std::string &name)
350 {
351         ASSERT(ref == m_ref);
352         if (m_parser.m_name.size())
353                 name = m_parser.m_name;
354         else
355         {
356                 name = ref.path;
357                 size_t n = name.rfind('/');
358                 if (n != std::string::npos)
359                         name = name.substr(n + 1);
360         }
361         return 0;
362 }
363
364 int eStaticServiceDVBPVRInformation::getLength(const eServiceReference &ref)
365 {
366         ASSERT(ref == m_ref);
367         
368         eDVBTSTools tstools;
369         
370         struct stat s;
371         stat(ref.path.c_str(), &s);
372
373         if (tstools.openFile(ref.path.c_str(), 1))
374                 return 0;
375
376                         /* check if cached data is still valid */
377         if (m_parser.m_data_ok && (s.st_size == m_parser.m_filesize) && (m_parser.m_length))
378                 return m_parser.m_length / 90000;
379
380                         /* open again, this time with stream info */
381         if (tstools.openFile(ref.path.c_str()))
382                 return 0;
383
384                         /* otherwise, re-calc length and update meta file */
385         pts_t len;
386         if (tstools.calcLen(len))
387                 return 0;
388
389         m_parser.m_length = len;
390         m_parser.m_filesize = s.st_size;
391         m_parser.updateMeta(ref.path);
392         return m_parser.m_length / 90000;
393 }
394
395 int eStaticServiceDVBPVRInformation::getInfo(const eServiceReference &ref, int w)
396 {
397         switch (w)
398         {
399         case iServiceInformation::sDescription:
400                 return iServiceInformation::resIsString;
401         case iServiceInformation::sServiceref:
402                 return iServiceInformation::resIsString;
403         case iServiceInformation::sFileSize:
404                 return m_parser.m_filesize;
405         case iServiceInformation::sTimeCreate:
406                 if (m_parser.m_time_create)
407                         return m_parser.m_time_create;
408                 else
409                         return iServiceInformation::resNA;
410         default:
411                 return iServiceInformation::resNA;
412         }
413 }
414
415 std::string eStaticServiceDVBPVRInformation::getInfoString(const eServiceReference &ref,int w)
416 {
417         switch (w)
418         {
419         case iServiceInformation::sDescription:
420                 return m_parser.m_description;
421         case iServiceInformation::sServiceref:
422                 return m_parser.m_ref.toString();
423         case iServiceInformation::sTags:
424                 return m_parser.m_tags;
425         default:
426                 return "";
427         }
428 }
429
430 RESULT eStaticServiceDVBPVRInformation::getEvent(const eServiceReference &ref, ePtr<eServiceEvent> &evt, time_t start_time)
431 {
432         if (!ref.path.empty())
433         {
434                 ePtr<eServiceEvent> event = new eServiceEvent;
435                 std::string filename = ref.path;
436                 filename.erase(filename.length()-2, 2);
437                 filename+="eit";
438                 if (!event->parseFrom(filename, (m_parser.m_ref.getTransportStreamID().get()<<16)|m_parser.m_ref.getOriginalNetworkID().get()))
439                 {
440                         evt = event;
441                         return 0;
442                 }
443         }
444         evt = 0;
445         return -1;
446 }
447
448 class eDVBPVRServiceOfflineOperations: public iServiceOfflineOperations
449 {
450         DECLARE_REF(eDVBPVRServiceOfflineOperations);
451         eServiceReferenceDVB m_ref;
452 public:
453         eDVBPVRServiceOfflineOperations(const eServiceReference &ref);
454         
455         RESULT deleteFromDisk(int simulate);
456         RESULT getListOfFilenames(std::list<std::string> &);
457 };
458
459 DEFINE_REF(eDVBPVRServiceOfflineOperations);
460
461 eDVBPVRServiceOfflineOperations::eDVBPVRServiceOfflineOperations(const eServiceReference &ref): m_ref((const eServiceReferenceDVB&)ref)
462 {
463 }
464
465 RESULT eDVBPVRServiceOfflineOperations::deleteFromDisk(int simulate)
466 {
467         if (simulate)
468                 return 0;
469         else
470         {
471                 std::list<std::string> res;
472                 if (getListOfFilenames(res))
473                         return -1;
474                 
475                 eBackgroundFileEraser *eraser = eBackgroundFileEraser::getInstance();
476                 if (!eraser)
477                         eDebug("FATAL !! can't get background file eraser");
478                 
479                 for (std::list<std::string>::iterator i(res.begin()); i != res.end(); ++i)
480                 {
481                         eDebug("Removing %s...", i->c_str());
482                         if (eraser)
483                                 eraser->erase(i->c_str());
484                         else
485                                 ::unlink(i->c_str());
486                 }
487                 
488                 return 0;
489         }
490 }
491
492 RESULT eDVBPVRServiceOfflineOperations::getListOfFilenames(std::list<std::string> &res)
493 {
494         res.clear();
495         res.push_back(m_ref.path);
496
497 // handling for old splitted recordings (enigma 1)
498         char buf[255];
499         int slice=1;
500         while(true)
501         {
502                 snprintf(buf, 255, "%s.%03d", m_ref.path.c_str(), slice++);
503                 struct stat s;
504                 if (stat(buf, &s) < 0)
505                         break;
506                 res.push_back(buf);
507         }       
508
509         res.push_back(m_ref.path + ".meta");
510         res.push_back(m_ref.path + ".ap");
511         res.push_back(m_ref.path + ".sc");
512         res.push_back(m_ref.path + ".cuts");
513         std::string tmp = m_ref.path;
514         tmp.erase(m_ref.path.length()-3);
515         res.push_back(tmp + ".eit");
516         return 0;
517 }
518
519 DEFINE_REF(eServiceFactoryDVB)
520
521 eServiceFactoryDVB::eServiceFactoryDVB()
522 {
523         ePtr<eServiceCenter> sc;
524         
525         eServiceCenter::getPrivInstance(sc);
526         if (sc)
527         {
528                 std::list<std::string> extensions;
529                 extensions.push_back("ts");
530                 extensions.push_back("trp");
531                 sc->addServiceFactory(eServiceFactoryDVB::id, this, extensions);
532         }
533
534         m_StaticServiceDVBInfo = new eStaticServiceDVBInformation;
535         m_StaticServiceDVBBouquetInfo = new eStaticServiceDVBBouquetInformation;
536 }
537
538 eServiceFactoryDVB::~eServiceFactoryDVB()
539 {
540         ePtr<eServiceCenter> sc;
541         
542         eServiceCenter::getPrivInstance(sc);
543         if (sc)
544                 sc->removeServiceFactory(eServiceFactoryDVB::id);
545 }
546
547 DEFINE_REF(eDVBServiceList);
548
549 eDVBServiceList::eDVBServiceList(const eServiceReference &parent): m_parent(parent)
550 {
551 }
552
553 eDVBServiceList::~eDVBServiceList()
554 {
555 }
556
557 RESULT eDVBServiceList::startQuery()
558 {
559         ePtr<iDVBChannelList> db;
560         ePtr<eDVBResourceManager> res;
561         
562         int err;
563         if ((err = eDVBResourceManager::getInstance(res)) != 0)
564         {
565                 eDebug("no resource manager");
566                 return err;
567         }
568         if ((err = res->getChannelList(db)) != 0)
569         {
570                 eDebug("no channel list");
571                 return err;
572         }
573         
574         ePtr<eDVBChannelQuery> q;
575         
576         if (!m_parent.path.empty())
577         {
578                 eDVBChannelQuery::compile(q, m_parent.path);
579                 if (!q)
580                 {
581                         eDebug("compile query failed");
582                         return err;
583                 }
584         }
585         
586         if ((err = db->startQuery(m_query, q, m_parent)) != 0)
587         {
588                 eDebug("startQuery failed");
589                 return err;
590         }
591
592         return 0;
593 }
594
595 RESULT eDVBServiceList::getContent(std::list<eServiceReference> &list, bool sorted)
596 {
597         eServiceReferenceDVB ref;
598         
599         if (!m_query)
600                 return -1;
601
602         while (!m_query->getNextResult(ref))
603                 list.push_back(ref);
604
605         if (sorted)
606                 list.sort(iListableServiceCompare(this));
607
608         return 0;
609 }
610
611 //   The first argument of this function is a format string to specify the order and
612 //   the content of the returned list
613 //   useable format options are
614 //   R = Service Reference (as swig object .. this is very slow)
615 //   S = Service Reference (as python string object .. same as ref.toString())
616 //   C = Service Reference (as python string object .. same as ref.toCompareString())
617 //   N = Service Name (as python string object)
618 //   n = Short Service Name (short name brakets used) (as python string object)
619 //   when exactly one return value per service is selected in the format string,
620 //   then each value is directly a list entry
621 //   when more than one value is returned per service, then the list is a list of
622 //   python tuples
623 //   unknown format string chars are returned as python None values !
624 PyObject *eDVBServiceList::getContent(const char* format, bool sorted)
625 {
626         ePyObject ret;
627         std::list<eServiceReference> tmplist;
628         int retcount=1;
629
630         if (!format || !(retcount=strlen(format)))
631                 format = "R"; // just return service reference swig object ...
632
633         if (!getContent(tmplist, sorted))
634         {
635                 int services=tmplist.size();
636                 ePtr<iStaticServiceInformation> sptr;
637                 eServiceCenterPtr service_center;
638
639                 if (strchr(format, 'N') || strchr(format, 'n'))
640                         eServiceCenter::getPrivInstance(service_center);
641
642                 ret = PyList_New(services);
643                 std::list<eServiceReference>::iterator it(tmplist.begin());
644
645                 for (int cnt=0; cnt < services; ++cnt)
646                 {
647                         eServiceReference &ref=*it++;
648                         ePyObject tuple = retcount > 1 ? PyTuple_New(retcount) : ePyObject();
649                         for (int i=0; i < retcount; ++i)
650                         {
651                                 ePyObject tmp;
652                                 switch(format[i])
653                                 {
654                                 case 'R':  // service reference (swig)object
655                                         tmp = NEW_eServiceReference(ref);
656                                         break;
657                                 case 'C':  // service reference compare string
658                                         tmp = PyString_FromString(ref.toCompareString().c_str());
659                                         break;
660                                 case 'S':  // service reference string
661                                         tmp = PyString_FromString(ref.toString().c_str());
662                                         break;
663                                 case 'N':  // service name
664                                         if (service_center)
665                                         {
666                                                 service_center->info(ref, sptr);
667                                                 if (sptr)
668                                                 {
669                                                         std::string name;
670                                                         sptr->getName(ref, name);
671
672                                                         // filter short name brakets
673                                                         size_t pos;
674                                                         while((pos = name.find("\xc2\x86")) != std::string::npos)
675                                                                 name.erase(pos,2);
676                                                         while((pos = name.find("\xc2\x87")) != std::string::npos)
677                                                                 name.erase(pos,2);
678
679                                                         if (name.length())
680                                                                 tmp = PyString_FromString(name.c_str());
681                                                 }
682                                         }
683                                         if (!tmp)
684                                                 tmp = PyString_FromString("<n/a>");
685                                         break;
686                                 case 'n':  // short service name
687                                         if (service_center)
688                                         {
689                                                 service_center->info(ref, sptr);
690                                                 if (sptr)
691                                                 {
692                                                         std::string name;
693                                                         sptr->getName(ref, name);
694                                                         name = buildShortName(name);
695                                                         if (name.length())
696                                                                 tmp = PyString_FromString(name.c_str());
697                                                 }
698                                         }
699                                         if (!tmp)
700                                                 tmp = PyString_FromString("<n/a>");
701                                         break;
702                                 default:
703                                         if (tuple)
704                                         {
705                                                 tmp = Py_None;
706                                                 Py_INCREF(Py_None);
707                                         }
708                                         break;
709                                 }
710                                 if (tmp)
711                                 {
712                                         if (tuple)
713                                                 PyTuple_SET_ITEM(tuple, i, tmp);
714                                         else
715                                                 PyList_SET_ITEM(ret, cnt, tmp);
716                                 }
717                         }
718                         if (tuple)
719                                 PyList_SET_ITEM(ret, cnt, tuple);
720                 }
721         }
722         return ret ? (PyObject*)ret : (PyObject*)PyList_New(0);
723 }
724
725 RESULT eDVBServiceList::getNext(eServiceReference &ref)
726 {
727         if (!m_query)
728                 return -1;
729         
730         return m_query->getNextResult((eServiceReferenceDVB&)ref);
731 }
732
733 RESULT eDVBServiceList::startEdit(ePtr<iMutableServiceList> &res)
734 {
735         if (m_parent.flags & eServiceReference::canDescent) // bouquet
736         {
737                 ePtr<iDVBChannelList> db;
738                 ePtr<eDVBResourceManager> resm;
739
740                 if (eDVBResourceManager::getInstance(resm) || resm->getChannelList(db))
741                         return -1;
742
743                 if (db->getBouquet(m_parent, m_bouquet) != 0)
744                         return -1;
745
746                 res = this;
747                 
748                 return 0;
749         }
750         res = 0;
751         return -1;
752 }
753
754 RESULT eDVBServiceList::addService(eServiceReference &ref, eServiceReference before)
755 {
756         if (!m_bouquet)
757                 return -1;
758         return m_bouquet->addService(ref, before);
759 }
760
761 RESULT eDVBServiceList::removeService(eServiceReference &ref)
762 {
763         if (!m_bouquet)
764                 return -1;
765         return m_bouquet->removeService(ref);
766 }
767
768 RESULT eDVBServiceList::moveService(eServiceReference &ref, int pos)
769 {
770         if (!m_bouquet)
771                 return -1;
772         return m_bouquet->moveService(ref, pos);
773 }
774
775 RESULT eDVBServiceList::flushChanges()
776 {
777         if (!m_bouquet)
778                 return -1;
779         return m_bouquet->flushChanges();
780 }
781
782 RESULT eDVBServiceList::setListName(const std::string &name)
783 {
784         if (!m_bouquet)
785                 return -1;
786         return m_bouquet->setListName(name);
787 }
788
789 RESULT eServiceFactoryDVB::play(const eServiceReference &ref, ePtr<iPlayableService> &ptr)
790 {
791         ePtr<eDVBService> service;
792         int r = lookupService(service, ref);
793         if (r)
794                 service = 0;
795                 // check resources...
796         ptr = new eDVBServicePlay(ref, service);
797         return 0;
798 }
799
800 RESULT eServiceFactoryDVB::record(const eServiceReference &ref, ePtr<iRecordableService> &ptr)
801 {
802         if (ref.path.empty())
803         {
804                 ptr = new eDVBServiceRecord((eServiceReferenceDVB&)ref);
805                 return 0;
806         } else
807         {
808                 ptr = 0;
809                 return -1;
810         }
811 }
812
813 RESULT eServiceFactoryDVB::list(const eServiceReference &ref, ePtr<iListableService> &ptr)
814 {
815         ePtr<eDVBServiceList> list = new eDVBServiceList(ref);
816         if (list->startQuery())
817         {
818                 ptr = 0;
819                 return -1;
820         }
821         
822         ptr = list;
823         return 0;
824 }
825
826 RESULT eServiceFactoryDVB::info(const eServiceReference &ref, ePtr<iStaticServiceInformation> &ptr)
827 {
828         /* is a listable service? */
829         if (ref.flags & eServiceReference::canDescent) // bouquet
830         {
831                 if ( !ref.name.empty() )  // satellites or providers list
832                         ptr = m_StaticServiceDVBInfo;
833                 else // a dvb bouquet
834                         ptr = m_StaticServiceDVBBouquetInfo;
835         }
836         else if (!ref.path.empty()) /* do we have a PVR service? */
837                 ptr = new eStaticServiceDVBPVRInformation(ref);
838         else // normal dvb service
839         {
840                 ePtr<eDVBService> service;
841                 if (lookupService(service, ref)) // no eDVBService avail for this reference ( Linkage Services... )
842                         ptr = m_StaticServiceDVBInfo;
843                 else
844                         /* eDVBService has the iStaticServiceInformation interface, so we pass it here. */
845                         ptr = service;
846         }
847         return 0;
848 }
849
850 RESULT eServiceFactoryDVB::offlineOperations(const eServiceReference &ref, ePtr<iServiceOfflineOperations> &ptr)
851 {
852         if (ref.path.empty())
853         {
854                 ptr = 0;
855                 return -1;
856         } else
857         {
858                 ptr = new eDVBPVRServiceOfflineOperations(ref);
859                 return 0;
860         }
861 }
862
863 RESULT eServiceFactoryDVB::lookupService(ePtr<eDVBService> &service, const eServiceReference &ref)
864 {
865         if (!ref.path.empty()) // playback
866         {
867                 eDVBMetaParser parser;
868                 int ret=parser.parseFile(ref.path);
869                 service = new eDVBService;
870                 if (!ret)
871                         eDVBDB::getInstance()->parseServiceData(service, parser.m_service_data);
872         }
873         else
874         {
875                         // TODO: handle the listing itself
876                 // if (ref.... == -1) .. return "... bouquets ...";
877                 // could be also done in another serviceFactory (with seperate ID) to seperate actual services and lists
878                         // TODO: cache
879                 ePtr<iDVBChannelList> db;
880                 ePtr<eDVBResourceManager> res;
881         
882                 int err;
883                 if ((err = eDVBResourceManager::getInstance(res)) != 0)
884                 {
885                         eDebug("no resource manager");
886                         return err;
887                 }
888                 if ((err = res->getChannelList(db)) != 0)
889                 {
890                         eDebug("no channel list");
891                         return err;
892                 }
893         
894                 /* we are sure to have a ..DVB reference as the info() call was forwarded here according to it's ID. */
895                 if ((err = db->getService((eServiceReferenceDVB&)ref, service)) != 0)
896                 {
897                         eDebug("getService failed!");
898                         return err;
899                 }
900         }
901
902         return 0;
903 }
904
905 eDVBServicePlay::eDVBServicePlay(const eServiceReference &ref, eDVBService *service): 
906         m_reference(ref), m_dvb_service(service), m_have_video_pid(0), m_is_paused(0)
907 {
908         m_is_primary = 1;
909         m_is_pvr = !m_reference.path.empty();
910         
911         m_timeshift_enabled = m_timeshift_active = 0;
912         m_skipmode = 0;
913         
914         CONNECT(m_service_handler.serviceEvent, eDVBServicePlay::serviceEvent);
915         CONNECT(m_service_handler_timeshift.serviceEvent, eDVBServicePlay::serviceEventTimeshift);
916         CONNECT(m_event_handler.m_eit_changed, eDVBServicePlay::gotNewEvent);
917
918         m_cuesheet_changed = 0;
919         m_cutlist_enabled = 1;
920         
921         m_subtitle_widget = 0;
922         
923         m_tune_state = -1;
924
925         m_subtitle_sync_timer = eTimer::create(eApp);
926
927         CONNECT(m_subtitle_sync_timer->timeout, eDVBServicePlay::checkSubtitleTiming);
928 }
929
930 eDVBServicePlay::~eDVBServicePlay()
931 {
932         if (m_is_pvr)
933         {
934                 eDVBMetaParser meta;
935                 int ret=meta.parseFile(m_reference.path);
936                 if (!ret)
937                 {
938                         char tmp[255];
939                         meta.m_service_data="";
940                         sprintf(tmp, "f:%x", m_dvb_service->m_flags);
941                         meta.m_service_data += tmp;
942                         // cached pids
943                         for (int x=0; x < eDVBService::cacheMax; ++x)
944                         {
945                                 int entry = m_dvb_service->getCacheEntry((eDVBService::cacheID)x);
946                                 if (entry != -1)
947                                 {
948                                         sprintf(tmp, ",c:%02d%04x", x, entry);
949                                         meta.m_service_data += tmp;
950                                 }
951                         }
952                         meta.updateMeta(m_reference.path);
953                 }
954         }
955         delete m_subtitle_widget;
956 }
957
958 void eDVBServicePlay::gotNewEvent()
959 {
960 #if 0
961                 // debug only
962         ePtr<eServiceEvent> m_event_now, m_event_next;
963         getEvent(m_event_now, 0);
964         getEvent(m_event_next, 1);
965
966         if (m_event_now)
967                 eDebug("now running: %s (%d seconds :)", m_event_now->m_event_name.c_str(), m_event_now->m_duration);
968         if (m_event_next)
969                 eDebug("next running: %s (%d seconds :)", m_event_next->m_event_name.c_str(), m_event_next->m_duration);
970 #endif
971         m_event((iPlayableService*)this, evUpdatedEventInfo);
972 }
973
974 void eDVBServicePlay::serviceEvent(int event)
975 {
976         m_tune_state = event;
977
978         switch (event)
979         {
980         case eDVBServicePMTHandler::eventTuned:
981         {
982                 ePtr<iDVBDemux> m_demux;
983                 if (!m_service_handler.getDataDemux(m_demux))
984                 {
985                         eServiceReferenceDVB &ref = (eServiceReferenceDVB&) m_reference;
986                         int sid = ref.getParentServiceID().get();
987                         if (!sid)
988                                 sid = ref.getServiceID().get();
989                         if ( ref.getParentTransportStreamID().get() &&
990                                 ref.getParentTransportStreamID() != ref.getTransportStreamID() )
991                                 m_event_handler.startOther(m_demux, sid);
992                         else
993                                 m_event_handler.start(m_demux, sid);
994                 }
995                 m_event((iPlayableService*)this, evTunedIn);
996                 break;
997         }
998         case eDVBServicePMTHandler::eventNoResources:
999         case eDVBServicePMTHandler::eventNoPAT:
1000         case eDVBServicePMTHandler::eventNoPATEntry:
1001         case eDVBServicePMTHandler::eventNoPMT:
1002         case eDVBServicePMTHandler::eventTuneFailed:
1003         case eDVBServicePMTHandler::eventMisconfiguration:
1004         {
1005                 eDebug("DVB service failed to tune - error %d", event);
1006                 m_event((iPlayableService*)this, evTuneFailed);
1007                 break;
1008         }
1009         case eDVBServicePMTHandler::eventNewProgramInfo:
1010         {
1011                 eDebug("eventNewProgramInfo %d %d", m_timeshift_enabled, m_timeshift_active);
1012                 if (m_timeshift_enabled)
1013                         updateTimeshiftPids();
1014                 if (!m_timeshift_active)
1015                         updateDecoder();
1016                 if (m_first_program_info && m_is_pvr)
1017                 {
1018                         m_first_program_info = 0;
1019                         seekTo(0);
1020                 }
1021                 m_event((iPlayableService*)this, evUpdatedInfo);
1022                 break;
1023         }
1024         case eDVBServicePMTHandler::eventEOF:
1025                 m_event((iPlayableService*)this, evEOF);
1026                 break;
1027         case eDVBServicePMTHandler::eventSOF:
1028                 m_event((iPlayableService*)this, evSOF);
1029                 break;
1030         }
1031 }
1032
1033 void eDVBServicePlay::serviceEventTimeshift(int event)
1034 {
1035         switch (event)
1036         {
1037         case eDVBServicePMTHandler::eventNewProgramInfo:
1038                 if (m_timeshift_active)
1039                         updateDecoder();
1040                 break;
1041         case eDVBServicePMTHandler::eventSOF:
1042                 m_event((iPlayableService*)this, evSOF);
1043                 break;
1044         case eDVBServicePMTHandler::eventEOF:
1045                 if ((!m_is_paused) && (m_skipmode >= 0))
1046                 {
1047                         eDebug("timeshift EOF, so let's go live");
1048                         switchToLive();
1049                 }
1050                 break;
1051         }
1052 }
1053
1054 RESULT eDVBServicePlay::start()
1055 {
1056         int r;
1057                 /* in pvr mode, we only want to use one demux. in tv mode, we're using 
1058                    two (one for decoding, one for data source), as we must be prepared
1059                    to start recording from the data demux. */
1060         if (m_is_pvr)
1061                 m_cue = new eCueSheet();
1062         else
1063                 m_event(this, evStart);
1064
1065         m_first_program_info = 1;
1066         eServiceReferenceDVB &service = (eServiceReferenceDVB&)m_reference;
1067         r = m_service_handler.tune(service, m_is_pvr, m_cue, false, m_dvb_service);
1068
1069                 /* inject EIT if there is a stored one */
1070         if (m_is_pvr)
1071         {
1072                 std::string filename = service.path;
1073                 filename.erase(filename.length()-2, 2);
1074                 filename+="eit";
1075                 ePtr<eServiceEvent> event = new eServiceEvent;
1076                 if (!event->parseFrom(filename, (service.getTransportStreamID().get()<<16)|service.getOriginalNetworkID().get()))
1077                 {
1078                         ePtr<eServiceEvent> empty;
1079                         m_event_handler.inject(event, 0);
1080                         m_event_handler.inject(empty, 1);
1081                 }
1082         }
1083
1084         if (m_is_pvr)
1085         {
1086                 loadCuesheet();
1087                 m_event(this, evStart);
1088         }
1089         return 0;
1090 }
1091
1092 RESULT eDVBServicePlay::stop()
1093 {
1094                 /* add bookmark for last play position */
1095         if (m_is_pvr)
1096         {
1097                 pts_t play_position, length;
1098                 if (!getPlayPosition(play_position))
1099                 {
1100                                 /* remove last position */
1101                         for (std::multiset<struct cueEntry>::iterator i(m_cue_entries.begin()); i != m_cue_entries.end();)
1102                         {
1103                                 if (i->what == 3) /* current play position */
1104                                 {
1105                                         m_cue_entries.erase(i);
1106                                         i = m_cue_entries.begin();
1107                                         continue;
1108                                 } else
1109                                         ++i;
1110                         }
1111                         
1112                         if (getLength(length))
1113                                 length = 0;
1114                         
1115                         if (length)
1116                         {
1117                                 int perc = play_position * 100LL / length;
1118                         
1119                                         /* only store last play position when between 1% and 99% */
1120                                 if ((1 < perc) && (perc < 99))
1121                                         m_cue_entries.insert(cueEntry(play_position, 3)); /* last play position */
1122                         }
1123                         m_cuesheet_changed = 1;
1124                 }
1125         }
1126
1127         stopTimeshift(); /* in case timeshift was enabled, remove buffer etc. */
1128
1129         m_service_handler_timeshift.free();
1130         m_service_handler.free();
1131         
1132         if (m_is_pvr && m_cuesheet_changed)
1133         {
1134                 struct stat s;
1135                                 /* save cuesheet only when main file is accessible. */
1136                 if (!::stat(m_reference.path.c_str(), &s))
1137                         saveCuesheet();
1138         }
1139         m_event((iPlayableService*)this, evStopped);
1140         return 0;
1141 }
1142
1143 RESULT eDVBServicePlay::setTarget(int target)
1144 {
1145         m_is_primary = !target;
1146         return 0;
1147 }
1148
1149 RESULT eDVBServicePlay::connectEvent(const Slot2<void,iPlayableService*,int> &event, ePtr<eConnection> &connection)
1150 {
1151         connection = new eConnection((iPlayableService*)this, m_event.connect(event));
1152         return 0;
1153 }
1154
1155 RESULT eDVBServicePlay::pause(ePtr<iPauseableService> &ptr)
1156 {
1157                 /* note: we check for timeshift to be enabled,
1158                    not neccessary active. if you pause when timeshift
1159                    is not active, you should activate it when unpausing */
1160         if ((!m_is_pvr) && (!m_timeshift_enabled))
1161         {
1162                 ptr = 0;
1163                 return -1;
1164         }
1165
1166         ptr = this;
1167         return 0;
1168 }
1169
1170 RESULT eDVBServicePlay::setSlowMotion(int ratio)
1171 {
1172         ASSERT(ratio); /* The API changed: instead of calling setSlowMotion(0), call play! */
1173         eDebug("eDVBServicePlay::setSlowMotion(%d)", ratio);
1174         setFastForward_internal(0);
1175         if (m_decoder)
1176                 return m_decoder->setSlowMotion(ratio);
1177         else
1178                 return -1;
1179 }
1180
1181 RESULT eDVBServicePlay::setFastForward(int ratio)
1182 {
1183         eDebug("eDVBServicePlay::setFastForward(%d)", ratio);
1184         ASSERT(ratio);
1185         return setFastForward_internal(ratio);
1186 }
1187
1188 RESULT eDVBServicePlay::setFastForward_internal(int ratio)
1189 {
1190         int skipmode, ffratio;
1191         
1192         if (ratio > 8)
1193         {
1194                 skipmode = ratio;
1195                 ffratio = 1;
1196         } else if (ratio > 0)
1197         {
1198                 skipmode = 0;
1199                 ffratio = ratio;
1200         } else if (!ratio)
1201         {
1202                 skipmode = 0;
1203                 ffratio = 0;
1204         } else // if (ratio < 0)
1205         {
1206                 skipmode = ratio;
1207                 ffratio = 1;
1208         }
1209
1210         if (m_skipmode != skipmode)
1211         {
1212                 eDebug("setting cue skipmode to %d", skipmode);
1213                 if (m_cue)
1214                         m_cue->setSkipmode(skipmode * 90000); /* convert to 90000 per second */
1215         }
1216         
1217         m_skipmode = skipmode;
1218         
1219         if (!m_decoder)
1220                 return -1;
1221                 
1222         if (ffratio == 0)
1223                 ; /* return m_decoder->play(); is done in caller*/
1224         else if (ffratio != 1)
1225                 return m_decoder->setFastForward(ffratio);
1226         else
1227                 return m_decoder->setTrickmode();
1228         return 0;
1229 }
1230
1231 RESULT eDVBServicePlay::seek(ePtr<iSeekableService> &ptr)
1232 {
1233         if (m_is_pvr || m_timeshift_enabled)
1234         {
1235                 ptr = this;
1236                 return 0;
1237         }
1238         
1239         ptr = 0;
1240         return -1;
1241 }
1242
1243         /* TODO: when timeshift is enabled but not active, this doesn't work. */
1244 RESULT eDVBServicePlay::getLength(pts_t &len)
1245 {
1246         ePtr<iDVBPVRChannel> pvr_channel;
1247         
1248         if ((m_timeshift_enabled ? m_service_handler_timeshift : m_service_handler).getPVRChannel(pvr_channel))
1249                 return -1;
1250         
1251         return pvr_channel->getLength(len);
1252 }
1253
1254 RESULT eDVBServicePlay::pause()
1255 {
1256         eDebug("eDVBServicePlay::pause");
1257         setFastForward_internal(0);
1258         if (m_decoder)
1259         {
1260                 m_is_paused = 1;
1261                 return m_decoder->pause();
1262         } else
1263                 return -1;
1264 }
1265
1266 RESULT eDVBServicePlay::unpause()
1267 {
1268         eDebug("eDVBServicePlay::unpause");
1269         setFastForward_internal(0);
1270         if (m_decoder)
1271         {
1272                 m_is_paused = 0;
1273                 return m_decoder->play();
1274         } else
1275                 return -1;
1276 }
1277
1278 RESULT eDVBServicePlay::seekTo(pts_t to)
1279 {
1280         eDebug("eDVBServicePlay::seekTo: jump %lld", to);
1281         
1282         if (!m_decode_demux)
1283                 return -1;
1284
1285         ePtr<iDVBPVRChannel> pvr_channel;
1286         
1287         if ((m_timeshift_enabled ? m_service_handler_timeshift : m_service_handler).getPVRChannel(pvr_channel))
1288                 return -1;
1289         
1290         if (!m_cue)
1291                 return -1;
1292         
1293         m_cue->seekTo(0, to);
1294         m_dvb_subtitle_pages.clear();
1295         m_subtitle_pages.clear();
1296
1297         return 0;
1298 }
1299
1300 RESULT eDVBServicePlay::seekRelative(int direction, pts_t to)
1301 {
1302         eDebug("eDVBServicePlay::seekRelative: jump %d, %lld", direction, to);
1303         
1304         if (!m_decode_demux)
1305                 return -1;
1306
1307         ePtr<iDVBPVRChannel> pvr_channel;
1308         
1309         if ((m_timeshift_enabled ? m_service_handler_timeshift : m_service_handler).getPVRChannel(pvr_channel))
1310                 return -1;
1311         
1312         int mode = 1;
1313         
1314                         /* HACK until we have skip-AP api */
1315         if ((to > 0) && (to < 100))
1316                 mode = 2;
1317         
1318         to *= direction;
1319         
1320         if (!m_cue)
1321                 return 0;
1322         
1323         m_cue->seekTo(mode, to);
1324         m_dvb_subtitle_pages.clear();
1325         m_subtitle_pages.clear();
1326         return 0;
1327 }
1328
1329 RESULT eDVBServicePlay::getPlayPosition(pts_t &pos)
1330 {
1331         ePtr<iDVBPVRChannel> pvr_channel;
1332         
1333         if (!m_decode_demux)
1334                 return -1;
1335         
1336         if ((m_timeshift_enabled ? m_service_handler_timeshift : m_service_handler).getPVRChannel(pvr_channel))
1337                 return -1;
1338         
1339         int r = 0;
1340
1341                 /* if there is a decoder, use audio or video PTS */
1342         if (m_decoder)
1343         {
1344                 r = m_decoder->getPTS(0, pos);
1345                 if (r)
1346                         return r;
1347         }
1348         
1349                 /* fixup */
1350         return pvr_channel->getCurrentPosition(m_decode_demux, pos, m_decoder ? 1 : 0);
1351 }
1352
1353 RESULT eDVBServicePlay::setTrickmode(int trick)
1354 {
1355                 /* currently unimplemented */
1356         return -1;
1357 }
1358
1359 RESULT eDVBServicePlay::isCurrentlySeekable()
1360 {
1361         return m_is_pvr || m_timeshift_active;
1362 }
1363
1364 RESULT eDVBServicePlay::frontendInfo(ePtr<iFrontendInformation> &ptr)
1365 {
1366         ptr = this;
1367         return 0;
1368 }
1369
1370 RESULT eDVBServicePlay::info(ePtr<iServiceInformation> &ptr)
1371 {
1372         ptr = this;
1373         return 0;
1374 }
1375
1376 RESULT eDVBServicePlay::audioChannel(ePtr<iAudioChannelSelection> &ptr)
1377 {
1378         ptr = this;
1379         return 0;
1380 }
1381
1382 RESULT eDVBServicePlay::audioTracks(ePtr<iAudioTrackSelection> &ptr)
1383 {
1384         ptr = this;
1385         return 0;
1386 }
1387
1388 RESULT eDVBServicePlay::subServices(ePtr<iSubserviceList> &ptr)
1389 {
1390         ptr = this;
1391         return 0;
1392 }
1393
1394 RESULT eDVBServicePlay::timeshift(ePtr<iTimeshiftService> &ptr)
1395 {
1396         ptr = 0;
1397         if (m_have_video_pid &&  // HACK !!! FIXMEE !! temporary no timeshift on radio services !!
1398                 (m_timeshift_enabled || !m_is_pvr))
1399         {
1400                 if (!m_timeshift_enabled)
1401                 {
1402                         /* query config path */
1403                         std::string tspath;
1404                         if(ePythonConfigQuery::getConfigValue("config.usage.timeshift_path", tspath) == -1){
1405                                 eDebug("could not query ts path from config");
1406                                 return -4;
1407                         }
1408                         tspath.append("/");
1409                         /* we need enough diskspace */
1410                         struct statfs fs;
1411                         if (statfs(tspath.c_str(), &fs) < 0)
1412                         {
1413                                 eDebug("statfs failed!");
1414                                 return -2;
1415                         }
1416                 
1417                         if (((off_t)fs.f_bavail) * ((off_t)fs.f_bsize) < 1024*1024*1024LL)
1418                         {
1419                                 eDebug("not enough diskspace for timeshift! (less than 1GB)");
1420                                 return -3;
1421                         }
1422                 }
1423                 ptr = this;
1424                 return 0;
1425         }
1426         return -1;
1427 }
1428
1429 RESULT eDVBServicePlay::cueSheet(ePtr<iCueSheet> &ptr)
1430 {
1431         if (m_is_pvr)
1432         {
1433                 ptr = this;
1434                 return 0;
1435         }
1436         ptr = 0;
1437         return -1;
1438 }
1439
1440 RESULT eDVBServicePlay::subtitle(ePtr<iSubtitleOutput> &ptr)
1441 {
1442         ptr = this;
1443         return 0;
1444 }
1445
1446 RESULT eDVBServicePlay::audioDelay(ePtr<iAudioDelay> &ptr)
1447 {
1448         ptr = this;
1449         return 0;
1450 }
1451
1452 RESULT eDVBServicePlay::rdsDecoder(ePtr<iRdsDecoder> &ptr)
1453 {
1454         ptr = this;
1455         return 0;
1456 }
1457
1458 RESULT eDVBServicePlay::getName(std::string &name)
1459 {
1460         if (m_is_pvr)
1461         {
1462                 ePtr<iStaticServiceInformation> i = new eStaticServiceDVBPVRInformation(m_reference);
1463                 return i->getName(m_reference, name);
1464         }
1465         else if (m_dvb_service)
1466         {
1467                 m_dvb_service->getName(m_reference, name);
1468                 if (name.empty())
1469                         name = "(...)";
1470         }
1471         else if (!m_reference.name.empty())
1472                 eStaticServiceDVBInformation().getName(m_reference, name);
1473         else
1474                 name = "DVB service";
1475         return 0;
1476 }
1477
1478 RESULT eDVBServicePlay::getEvent(ePtr<eServiceEvent> &evt, int nownext)
1479 {
1480         return m_event_handler.getEvent(evt, nownext);
1481 }
1482
1483 int eDVBServicePlay::getInfo(int w)
1484 {
1485         eDVBServicePMTHandler::program program;
1486
1487         if (w == sCAIDs)
1488                 return resIsPyObject;
1489
1490         eDVBServicePMTHandler &h = m_timeshift_active ? m_service_handler_timeshift : m_service_handler;
1491
1492         int no_program_info = 0;
1493
1494         if (h.getProgramInfo(program))
1495                 no_program_info = 1;
1496
1497         switch (w)
1498         {
1499         case sVideoHeight:
1500                 if (m_decoder)
1501                         return m_decoder->getVideoHeight();
1502                 break;
1503         case sVideoWidth:
1504                 if (m_decoder)
1505                         return m_decoder->getVideoWidth();
1506                 break;
1507         case sFrameRate:
1508                 if (m_decoder)
1509                         return m_decoder->getVideoFrameRate();
1510                 break;
1511         case sProgressive:
1512                 if (m_decoder)
1513                         return m_decoder->getVideoProgressive();
1514                 break;
1515         case sAspect:
1516         {
1517                 int aspect = -1;
1518                 if (m_decoder)
1519                         aspect = m_decoder->getVideoAspect();
1520                 if (no_program_info)
1521                         break;
1522                 else if (aspect == -1 && !program.videoStreams.empty() && program.videoStreams[0].component_tag != -1)
1523                 {
1524                         ePtr<eServiceEvent> evt;
1525                         if (!m_event_handler.getEvent(evt, 0))
1526                         {
1527                                 ePtr<eComponentData> data;
1528                                 if (!evt->getComponentData(data, program.videoStreams[0].component_tag))
1529                                 {
1530                                         if ( data->getStreamContent() == 1 )
1531                                         {
1532                                                 switch(data->getComponentType())
1533                                                 {
1534                                                         // SD
1535                                                         case 1: // 4:3 SD PAL
1536                                                         case 2:
1537                                                         case 3: // 16:9 SD PAL
1538                                                         case 4: // > 16:9 PAL
1539                                                         case 5: // 4:3 SD NTSC
1540                                                         case 6: 
1541                                                         case 7: // 16:9 SD NTSC
1542                                                         case 8: // > 16:9 NTSC
1543
1544                                                         // HD
1545                                                         case 9: // 4:3 HD PAL
1546                                                         case 0xA:
1547                                                         case 0xB: // 16:9 HD PAL
1548                                                         case 0xC: // > 16:9 HD PAL
1549                                                         case 0xD: // 4:3 HD NTSC
1550                                                         case 0xE:
1551                                                         case 0xF: // 16:9 HD NTSC
1552                                                         case 0x10: // > 16:9 HD PAL
1553                                                                 return data->getComponentType();
1554                                                 }
1555                                         }
1556                                 }
1557                         }
1558                 }
1559                 else
1560                         return aspect;
1561                 break;
1562         }
1563         case sIsCrypted: if (no_program_info) return -1; return program.isCrypted();
1564         case sVideoPID:
1565                 if (m_dvb_service)
1566                 {
1567                         int vpid = m_dvb_service->getCacheEntry(eDVBService::cVPID);
1568                         if (vpid != -1)
1569                                 return vpid;
1570                 }
1571                 if (no_program_info) return -1; if (program.videoStreams.empty()) return -1; return program.videoStreams[0].pid;
1572         case sVideoType: if (no_program_info) return -1; if (program.videoStreams.empty()) return -1; return program.videoStreams[0].type;
1573         case sAudioPID:
1574                 if (m_dvb_service)
1575                 {
1576                         int apid = m_dvb_service->getCacheEntry(eDVBService::cAPID);
1577                         if (apid != -1)
1578                                 return apid;
1579                         apid = m_dvb_service->getCacheEntry(eDVBService::cAC3PID);
1580                         if (apid != -1)
1581                                 return apid;
1582                 }
1583                 if (no_program_info) return -1; if (program.audioStreams.empty()) return -1; return program.audioStreams[0].pid;
1584         case sPCRPID:
1585                 if (m_dvb_service)
1586                 {
1587                         int pcrpid = m_dvb_service->getCacheEntry(eDVBService::cPCRPID);
1588                         if (pcrpid != -1)
1589                                 return pcrpid;
1590                 }
1591                 if (no_program_info) return -1; return program.pcrPid;
1592         case sPMTPID: if (no_program_info) return -1; return program.pmtPid;
1593         case sTXTPID: if (no_program_info) return -1; return program.textPid;
1594         case sSID: return ((const eServiceReferenceDVB&)m_reference).getServiceID().get();
1595         case sONID: return ((const eServiceReferenceDVB&)m_reference).getOriginalNetworkID().get();
1596         case sTSID: return ((const eServiceReferenceDVB&)m_reference).getTransportStreamID().get();
1597         case sNamespace: return ((const eServiceReferenceDVB&)m_reference).getDVBNamespace().get();
1598         case sProvider: if (!m_dvb_service) return -1; return -2;
1599         case sServiceref: return resIsString;
1600         case sDVBState: return m_tune_state;
1601         default:
1602                 break;
1603         }
1604         return -1;
1605 }
1606
1607 std::string eDVBServicePlay::getInfoString(int w)
1608 {
1609         switch (w)
1610         {
1611         case sProvider:
1612                 if (!m_dvb_service) return "";
1613                 return m_dvb_service->m_provider_name;
1614         case sServiceref:
1615                 return m_reference.toString();
1616         default:
1617                 break;
1618         }
1619         return iServiceInformation::getInfoString(w);
1620 }
1621
1622 PyObject *eDVBServicePlay::getInfoObject(int w)
1623 {
1624         switch (w)
1625         {
1626         case sCAIDs:
1627                 return m_service_handler.getCaIds();
1628         case sTransponderData:
1629                 return eStaticServiceDVBInformation().getInfoObject(m_reference, w);
1630         default:
1631                 break;
1632         }
1633         return iServiceInformation::getInfoObject(w);
1634 }
1635
1636 int eDVBServicePlay::getNumberOfTracks()
1637 {
1638         eDVBServicePMTHandler::program program;
1639         eDVBServicePMTHandler &h = m_timeshift_active ? m_service_handler_timeshift : m_service_handler;
1640         if (h.getProgramInfo(program))
1641                 return 0;
1642         return program.audioStreams.size();
1643 }
1644
1645 int eDVBServicePlay::getCurrentTrack()
1646 {
1647         eDVBServicePMTHandler::program program;
1648         eDVBServicePMTHandler &h = m_timeshift_active ? m_service_handler_timeshift : m_service_handler;
1649         if (h.getProgramInfo(program))
1650                 return 0;
1651
1652         int max = program.audioStreams.size();
1653         int i;
1654
1655         for (i = 0; i < max; ++i)
1656                 if (program.audioStreams[i].pid == m_current_audio_pid)
1657                         return i;
1658
1659         return 0;
1660 }
1661
1662 RESULT eDVBServicePlay::selectTrack(unsigned int i)
1663 {
1664         int ret = selectAudioStream(i);
1665
1666         if (m_decoder->set())
1667                 return -5;
1668
1669         return ret;
1670 }
1671
1672 RESULT eDVBServicePlay::getTrackInfo(struct iAudioTrackInfo &info, unsigned int i)
1673 {
1674         eDVBServicePMTHandler::program program;
1675         eDVBServicePMTHandler &h = m_timeshift_active ? m_service_handler_timeshift : m_service_handler;
1676
1677         if (h.getProgramInfo(program))
1678                 return -1;
1679         
1680         if (i >= program.audioStreams.size())
1681                 return -2;
1682         
1683         info.m_pid = program.audioStreams[i].pid;
1684
1685         if (program.audioStreams[i].type == eDVBServicePMTHandler::audioStream::atMPEG)
1686                 info.m_description = "MPEG";
1687         else if (program.audioStreams[i].type == eDVBServicePMTHandler::audioStream::atAC3)
1688                 info.m_description = "AC3";
1689         else if (program.audioStreams[i].type == eDVBServicePMTHandler::audioStream::atAAC)
1690                 info.m_description = "AAC";
1691         else if (program.audioStreams[i].type == eDVBServicePMTHandler::audioStream::atAACHE)
1692                 info.m_description = "AAC-HE";
1693         else  if (program.audioStreams[i].type == eDVBServicePMTHandler::audioStream::atDTS)
1694                 info.m_description = "DTS";
1695         else
1696                 info.m_description = "???";
1697
1698         if (program.audioStreams[i].component_tag != -1)
1699         {
1700                 ePtr<eServiceEvent> evt;
1701                 if (!m_event_handler.getEvent(evt, 0))
1702                 {
1703                         ePtr<eComponentData> data;
1704                         if (!evt->getComponentData(data, program.audioStreams[i].component_tag))
1705                                 info.m_language = data->getText();
1706                 }
1707         }
1708
1709         if (info.m_language.empty())
1710                 info.m_language = program.audioStreams[i].language_code;
1711         
1712         return 0;
1713 }
1714
1715 int eDVBServicePlay::selectAudioStream(int i)
1716 {
1717         eDVBServicePMTHandler::program program;
1718         eDVBServicePMTHandler &h = m_timeshift_active ? m_service_handler_timeshift : m_service_handler;
1719
1720         if (h.getProgramInfo(program))
1721                 return -1;
1722
1723         if ((i != -1) && ((unsigned int)i >= program.audioStreams.size()))
1724                 return -2;
1725
1726         if (!m_decoder)
1727                 return -3;
1728
1729         int stream = i;
1730         if (stream == -1)
1731                 stream = program.defaultAudioStream;
1732
1733         int apid = -1, apidtype = -1;
1734
1735         if (((unsigned int)stream) < program.audioStreams.size())
1736         {
1737                 apid = program.audioStreams[stream].pid;
1738                 apidtype = program.audioStreams[stream].type;
1739         }
1740
1741         m_current_audio_pid = apid;
1742
1743         if (m_is_primary && m_decoder->setAudioPID(apid, apidtype))
1744         {
1745                 eDebug("set audio pid failed");
1746                 return -4;
1747         }
1748
1749                 /* if we are not in PVR mode, timeshift is not active and we are not in pip mode, check if we need to enable the rds reader */
1750         if (!(m_is_pvr || m_timeshift_active || !m_is_primary))
1751                 if (!m_rds_decoder)
1752                 {
1753                         ePtr<iDVBDemux> data_demux;
1754                         if (!h.getDataDemux(data_demux))
1755                         {
1756                                 m_rds_decoder = new eDVBRdsDecoder(data_demux);
1757                                 m_rds_decoder->connectEvent(slot(*this, &eDVBServicePlay::rdsDecoderEvent), m_rds_decoder_event_connection);
1758                         }
1759                 }
1760
1761                 /* if we decided that we need one, update the pid */
1762         if (m_rds_decoder)
1763                 m_rds_decoder->start(apid);
1764
1765                         /* store new pid as default only when:
1766                                 a.) we have an entry in the service db for the current service,
1767                                 b.) we are not playing back something,
1768                                 c.) we are not selecting the default entry. (we wouldn't change 
1769                                     anything in the best case, or destroy the default setting in
1770                                     case the real default is not yet available.)
1771                         */
1772         if (m_dvb_service && ((i != -1)
1773                 || ((m_dvb_service->getCacheEntry(eDVBService::cAPID) == -1) && (m_dvb_service->getCacheEntry(eDVBService::cAC3PID)==-1))))
1774         {
1775                 if (apidtype == eDVBAudio::aMPEG)
1776                 {
1777                         m_dvb_service->setCacheEntry(eDVBService::cAPID, apid);
1778                         m_dvb_service->setCacheEntry(eDVBService::cAC3PID, -1);
1779                 }
1780                 else if (apidtype == eDVBAudio::aAC3)
1781                 {
1782                         m_dvb_service->setCacheEntry(eDVBService::cAPID, -1);
1783                         m_dvb_service->setCacheEntry(eDVBService::cAC3PID, apid);
1784                 }
1785                 else
1786                 {
1787                         m_dvb_service->setCacheEntry(eDVBService::cAPID, -1);
1788                         m_dvb_service->setCacheEntry(eDVBService::cAC3PID, -1);
1789                 }
1790         }
1791
1792         h.resetCachedProgram();
1793
1794         return 0;
1795 }
1796
1797 int eDVBServicePlay::getCurrentChannel()
1798 {
1799         return m_decoder ? m_decoder->getAudioChannel() : STEREO;
1800 }
1801
1802 RESULT eDVBServicePlay::selectChannel(int i)
1803 {
1804         if (i < LEFT || i > RIGHT || i == STEREO)
1805                 i = -1;  // Stereo
1806         if (m_dvb_service)
1807                 m_dvb_service->setCacheEntry(eDVBService::cACHANNEL, i);
1808         if (m_decoder)
1809                 m_decoder->setAudioChannel(i);
1810         return 0;
1811 }
1812
1813 std::string eDVBServicePlay::getText(int x)
1814 {
1815         if (m_rds_decoder)
1816                 switch(x)
1817                 {
1818                         case RadioText:
1819                                 return convertLatin1UTF8(m_rds_decoder->getRadioText());
1820                         case RtpText:
1821                                 return convertLatin1UTF8(m_rds_decoder->getRtpText());
1822                 }
1823         return "";
1824 }
1825
1826 void eDVBServicePlay::rdsDecoderEvent(int what)
1827 {
1828         switch(what)
1829         {
1830                 case eDVBRdsDecoder::RadioTextChanged:
1831                         m_event((iPlayableService*)this, evUpdatedRadioText);
1832                         break;
1833                 case eDVBRdsDecoder::RtpTextChanged:
1834                         m_event((iPlayableService*)this, evUpdatedRtpText);
1835                         break;
1836                 case eDVBRdsDecoder::RassInteractivePicMaskChanged:
1837                         m_event((iPlayableService*)this, evUpdatedRassInteractivePicMask);
1838                         break;
1839                 case eDVBRdsDecoder::RecvRassSlidePic:
1840                         m_event((iPlayableService*)this, evUpdatedRassSlidePic);
1841                         break;
1842         }
1843 }
1844
1845 void eDVBServicePlay::showRassSlidePicture()
1846 {
1847         if (m_rds_decoder)
1848         {
1849                 if (m_decoder)
1850                 {
1851                         std::string rass_slide_pic = m_rds_decoder->getRassSlideshowPicture();
1852                         if (rass_slide_pic.length())
1853                                 m_decoder->showSinglePic(rass_slide_pic.c_str());
1854                         else
1855                                 eDebug("empty filename for rass slide picture received!!");
1856                 }
1857                 else
1858                         eDebug("no MPEG Decoder to show iframes avail");
1859         }
1860         else
1861                 eDebug("showRassSlidePicture called.. but not decoder");
1862 }
1863
1864 void eDVBServicePlay::showRassInteractivePic(int page, int subpage)
1865 {
1866         if (m_rds_decoder)
1867         {
1868                 if (m_decoder)
1869                 {
1870                         std::string rass_interactive_pic = m_rds_decoder->getRassPicture(page, subpage);
1871                         if (rass_interactive_pic.length())
1872                                 m_decoder->showSinglePic(rass_interactive_pic.c_str());
1873                         else
1874                                 eDebug("empty filename for rass interactive picture %d/%d received!!", page, subpage);
1875                 }
1876                 else
1877                         eDebug("no MPEG Decoder to show iframes avail");
1878         }
1879         else
1880                 eDebug("showRassInteractivePic called.. but not decoder");
1881 }
1882
1883 ePyObject eDVBServicePlay::getRassInteractiveMask()
1884 {
1885         if (m_rds_decoder)
1886                 return m_rds_decoder->getRassPictureMask();
1887         Py_RETURN_NONE;
1888 }
1889
1890 int eDVBServiceBase::getFrontendInfo(int w)
1891 {
1892         eUsePtr<iDVBChannel> channel;
1893         if(m_service_handler.getChannel(channel))
1894                 return 0;
1895         ePtr<iDVBFrontend> fe;
1896         if(channel->getFrontend(fe))
1897                 return 0;
1898         return fe->readFrontendData(w);
1899 }
1900
1901 PyObject *eDVBServiceBase::getFrontendData()
1902 {
1903         ePyObject ret = PyDict_New();
1904         if (ret)
1905         {
1906                 eUsePtr<iDVBChannel> channel;
1907                 if(!m_service_handler.getChannel(channel))
1908                 {
1909                         ePtr<iDVBFrontend> fe;
1910                         if(!channel->getFrontend(fe))
1911                                 fe->getFrontendData(ret);
1912                 }
1913         }
1914         else
1915                 Py_RETURN_NONE;
1916         return ret;
1917 }
1918
1919 PyObject *eDVBServiceBase::getFrontendStatus()
1920 {
1921         ePyObject ret = PyDict_New();
1922         if (ret)
1923         {
1924                 eUsePtr<iDVBChannel> channel;
1925                 if(!m_service_handler.getChannel(channel))
1926                 {
1927                         ePtr<iDVBFrontend> fe;
1928                         if(!channel->getFrontend(fe))
1929                                 fe->getFrontendStatus(ret);
1930                 }
1931         }
1932         else
1933                 Py_RETURN_NONE;
1934         return ret;
1935 }
1936
1937 PyObject *eDVBServiceBase::getTransponderData(bool original)
1938 {
1939         ePyObject ret = PyDict_New();
1940         if (ret)
1941         {
1942                 eUsePtr<iDVBChannel> channel;
1943                 if(!m_service_handler.getChannel(channel))
1944                 {
1945                         ePtr<iDVBFrontend> fe;
1946                         if(!channel->getFrontend(fe))
1947                                 fe->getTransponderData(ret, original);
1948                 }
1949         }
1950         else
1951                 Py_RETURN_NONE;
1952         return ret;
1953 }
1954
1955 PyObject *eDVBServiceBase::getAll(bool original)
1956 {
1957         ePyObject ret = getTransponderData(original);
1958         if (ret != Py_None)
1959         {
1960                 eUsePtr<iDVBChannel> channel;
1961                 if(!m_service_handler.getChannel(channel))
1962                 {
1963                         ePtr<iDVBFrontend> fe;
1964                         if(!channel->getFrontend(fe))
1965                         {
1966                                 fe->getFrontendData(ret);
1967                                 fe->getFrontendStatus(ret);
1968                         }
1969                 }
1970         }
1971         return ret;
1972 }
1973
1974 int eDVBServicePlay::getNumberOfSubservices()
1975 {
1976         ePtr<eServiceEvent> evt;
1977         if (!m_event_handler.getEvent(evt, 0))
1978                 return evt->getNumOfLinkageServices();
1979         return 0;
1980 }
1981
1982 RESULT eDVBServicePlay::getSubservice(eServiceReference &sub, unsigned int n)
1983 {
1984         ePtr<eServiceEvent> evt;
1985         if (!m_event_handler.getEvent(evt, 0))
1986         {
1987                 if (!evt->getLinkageService(sub, m_reference, n))
1988                         return 0;
1989         }
1990         sub.type=eServiceReference::idInvalid;
1991         return -1;
1992 }
1993
1994 RESULT eDVBServicePlay::startTimeshift()
1995 {
1996         ePtr<iDVBDemux> demux;
1997         
1998         eDebug("Start timeshift!");
1999         
2000         if (m_timeshift_enabled)
2001                 return -1;
2002         
2003                 /* start recording with the data demux. */
2004         if (m_service_handler.getDataDemux(demux))
2005                 return -2;
2006
2007         demux->createTSRecorder(m_record);
2008         if (!m_record)
2009                 return -3;
2010
2011         std::string tspath;
2012         if(ePythonConfigQuery::getConfigValue("config.usage.timeshift_path", tspath) == -1){ 
2013                 eDebug("could not query ts path");
2014                 return -5;
2015         }
2016         tspath.append("/timeshift.XXXXXX");
2017         char* templ;
2018         templ = new char[tspath.length() + 1];
2019         strcpy(templ, tspath.c_str());
2020
2021         m_timeshift_fd = mkstemp(templ);
2022         m_timeshift_file = std::string(templ);
2023
2024         eDebug("recording to %s", templ);
2025
2026         delete [] templ;
2027
2028         if (m_timeshift_fd < 0)
2029         {
2030                 m_record = 0;
2031                 return -4;
2032         }
2033                 
2034         m_record->setTargetFD(m_timeshift_fd);
2035
2036         m_timeshift_enabled = 1;
2037         
2038         updateTimeshiftPids();
2039         m_record->start();
2040
2041         return 0;
2042 }
2043
2044 RESULT eDVBServicePlay::stopTimeshift()
2045 {
2046         if (!m_timeshift_enabled)
2047                 return -1;
2048         
2049         switchToLive();
2050         
2051         m_timeshift_enabled = 0;
2052         
2053         m_record->stop();
2054         m_record = 0;
2055         
2056         close(m_timeshift_fd);
2057         eDebug("remove timeshift file");
2058         eBackgroundFileEraser::getInstance()->erase(m_timeshift_file.c_str());
2059         
2060         return 0;
2061 }
2062
2063 int eDVBServicePlay::isTimeshiftActive()
2064 {
2065         return m_timeshift_enabled && m_timeshift_active;
2066 }
2067
2068 RESULT eDVBServicePlay::activateTimeshift()
2069 {
2070         if (!m_timeshift_enabled)
2071                 return -1;
2072         
2073         if (!m_timeshift_active)
2074         {
2075                 switchToTimeshift();
2076                 return 0;
2077         }
2078         
2079         return -2;
2080 }
2081
2082 PyObject *eDVBServicePlay::getCutList()
2083 {
2084         ePyObject list = PyList_New(0);
2085         
2086         for (std::multiset<struct cueEntry>::iterator i(m_cue_entries.begin()); i != m_cue_entries.end(); ++i)
2087         {
2088                 ePyObject tuple = PyTuple_New(2);
2089                 PyTuple_SET_ITEM(tuple, 0, PyLong_FromLongLong(i->where));
2090                 PyTuple_SET_ITEM(tuple, 1, PyInt_FromLong(i->what));
2091                 PyList_Append(list, tuple);
2092                 Py_DECREF(tuple);
2093         }
2094         
2095         return list;
2096 }
2097
2098 void eDVBServicePlay::setCutList(ePyObject list)
2099 {
2100         if (!PyList_Check(list))
2101                 return;
2102         int size = PyList_Size(list);
2103         int i;
2104         
2105         m_cue_entries.clear();
2106         
2107         for (i=0; i<size; ++i)
2108         {
2109                 ePyObject tuple = PyList_GET_ITEM(list, i);
2110                 if (!PyTuple_Check(tuple))
2111                 {
2112                         eDebug("non-tuple in cutlist");
2113                         continue;
2114                 }
2115                 if (PyTuple_Size(tuple) != 2)
2116                 {
2117                         eDebug("cutlist entries need to be a 2-tuple");
2118                         continue;
2119                 }
2120                 ePyObject ppts = PyTuple_GET_ITEM(tuple, 0), ptype = PyTuple_GET_ITEM(tuple, 1);
2121                 if (!(PyLong_Check(ppts) && PyInt_Check(ptype)))
2122                 {
2123                         eDebug("cutlist entries need to be (pts, type)-tuples (%d %d)", PyLong_Check(ppts), PyInt_Check(ptype));
2124                         continue;
2125                 }
2126                 pts_t pts = PyLong_AsLongLong(ppts);
2127                 int type = PyInt_AsLong(ptype);
2128                 m_cue_entries.insert(cueEntry(pts, type));
2129                 eDebug("adding %08llx, %d", pts, type);
2130         }
2131         m_cuesheet_changed = 1;
2132         
2133         cutlistToCuesheet();
2134         m_event((iPlayableService*)this, evCuesheetChanged);
2135 }
2136
2137 void eDVBServicePlay::setCutListEnable(int enable)
2138 {
2139         m_cutlist_enabled = enable;
2140         cutlistToCuesheet();
2141 }
2142
2143 void eDVBServicePlay::updateTimeshiftPids()
2144 {
2145         if (!m_record)
2146                 return;
2147         
2148         eDVBServicePMTHandler::program program;
2149         eDVBServicePMTHandler &h = m_timeshift_active ? m_service_handler_timeshift : m_service_handler;
2150
2151         if (h.getProgramInfo(program))
2152                 return;
2153         else
2154         {
2155                 std::set<int> pids_to_record;
2156                 pids_to_record.insert(0); // PAT
2157                 if (program.pmtPid != -1)
2158                         pids_to_record.insert(program.pmtPid); // PMT
2159
2160                 if (program.textPid != -1)
2161                         pids_to_record.insert(program.textPid); // Videotext
2162
2163                 for (std::vector<eDVBServicePMTHandler::videoStream>::const_iterator
2164                         i(program.videoStreams.begin()); 
2165                         i != program.videoStreams.end(); ++i)
2166                         pids_to_record.insert(i->pid);
2167
2168                 for (std::vector<eDVBServicePMTHandler::audioStream>::const_iterator
2169                         i(program.audioStreams.begin()); 
2170                         i != program.audioStreams.end(); ++i)
2171                                 pids_to_record.insert(i->pid);
2172
2173                 for (std::vector<eDVBServicePMTHandler::subtitleStream>::const_iterator
2174                         i(program.subtitleStreams.begin());
2175                         i != program.subtitleStreams.end(); ++i)
2176                                 pids_to_record.insert(i->pid);
2177
2178                 std::set<int> new_pids, obsolete_pids;
2179                 
2180                 std::set_difference(pids_to_record.begin(), pids_to_record.end(), 
2181                                 m_pids_active.begin(), m_pids_active.end(),
2182                                 std::inserter(new_pids, new_pids.begin()));
2183                 
2184                 std::set_difference(
2185                                 m_pids_active.begin(), m_pids_active.end(),
2186                                 pids_to_record.begin(), pids_to_record.end(), 
2187                                 std::inserter(new_pids, new_pids.begin())
2188                                 );
2189
2190                 for (std::set<int>::iterator i(new_pids.begin()); i != new_pids.end(); ++i)
2191                         m_record->addPID(*i);
2192
2193                 for (std::set<int>::iterator i(obsolete_pids.begin()); i != obsolete_pids.end(); ++i)
2194                         m_record->removePID(*i);
2195         }
2196 }
2197
2198 void eDVBServicePlay::switchToLive()
2199 {
2200         if (!m_timeshift_active)
2201                 return;
2202         
2203         eDebug("SwitchToLive");
2204         
2205         m_cue = 0;
2206         m_decoder = 0;
2207         m_decode_demux = 0;
2208         m_teletext_parser = 0;
2209         m_rds_decoder = 0;
2210         m_subtitle_parser = 0;
2211         m_new_dvb_subtitle_page_connection = 0;
2212         m_new_subtitle_page_connection = 0;
2213         m_rds_decoder_event_connection = 0;
2214         m_video_event_connection = 0;
2215         m_is_paused = m_skipmode = 0; /* not supported in live mode */
2216
2217                 /* free the timeshift service handler, we need the resources */
2218         m_service_handler_timeshift.free();
2219         m_timeshift_active = 0;
2220
2221         m_event((iPlayableService*)this, evSeekableStatusChanged);
2222
2223         updateDecoder();
2224 }
2225
2226 void eDVBServicePlay::switchToTimeshift()
2227 {
2228         if (m_timeshift_active)
2229                 return;
2230
2231         m_decode_demux = 0;
2232         m_decoder = 0;
2233         m_teletext_parser = 0;
2234         m_rds_decoder = 0;
2235         m_subtitle_parser = 0;
2236         m_new_subtitle_page_connection = 0;
2237         m_new_dvb_subtitle_page_connection = 0;
2238         m_rds_decoder_event_connection = 0;
2239         m_video_event_connection = 0;
2240
2241         m_timeshift_active = 1;
2242
2243         eServiceReferenceDVB r = (eServiceReferenceDVB&)m_reference;
2244         r.path = m_timeshift_file;
2245
2246         m_cue = new eCueSheet();
2247         m_service_handler_timeshift.tune(r, 1, m_cue, 0, m_dvb_service); /* use the decoder demux for everything */
2248
2249         eDebug("eDVBServicePlay::switchToTimeshift, in pause mode now.");
2250         pause();
2251         updateDecoder(); /* mainly to switch off PCR, and to set pause */
2252         
2253         m_event((iPlayableService*)this, evSeekableStatusChanged);
2254 }
2255
2256 void eDVBServicePlay::updateDecoder()
2257 {
2258         int vpid = -1, vpidtype = -1, pcrpid = -1, tpid = -1, achannel = -1, ac3_delay=-1, pcm_delay=-1;
2259
2260         eDVBServicePMTHandler &h = m_timeshift_active ? m_service_handler_timeshift : m_service_handler;
2261
2262         eDVBServicePMTHandler::program program;
2263         if (h.getProgramInfo(program))
2264                 eDebug("getting program info failed.");
2265         else
2266         {
2267                 eDebugNoNewLine("have %d video stream(s)", program.videoStreams.size());
2268                 if (!program.videoStreams.empty())
2269                 {
2270                         eDebugNoNewLine(" (");
2271                         for (std::vector<eDVBServicePMTHandler::videoStream>::const_iterator
2272                                 i(program.videoStreams.begin());
2273                                 i != program.videoStreams.end(); ++i)
2274                         {
2275                                 if (vpid == -1)
2276                                 {
2277                                         vpid = i->pid;
2278                                         vpidtype = i->type;
2279                                 }
2280                                 if (i != program.videoStreams.begin())
2281                                         eDebugNoNewLine(", ");
2282                                 eDebugNoNewLine("%04x", i->pid);
2283                         }
2284                         eDebugNoNewLine(")");
2285                 }
2286                 eDebugNoNewLine(", and %d audio stream(s)", program.audioStreams.size());
2287                 if (!program.audioStreams.empty())
2288                 {
2289                         eDebugNoNewLine(" (");
2290                         for (std::vector<eDVBServicePMTHandler::audioStream>::const_iterator
2291                                 i(program.audioStreams.begin());
2292                                 i != program.audioStreams.end(); ++i)
2293                         {
2294                                 if (i != program.audioStreams.begin())
2295                                         eDebugNoNewLine(", ");
2296                                 eDebugNoNewLine("%04x", i->pid);
2297                         }
2298                         eDebugNoNewLine(")");
2299                 }
2300                 eDebugNoNewLine(", and the pcr pid is %04x", program.pcrPid);
2301                 pcrpid = program.pcrPid;
2302                 eDebug(", and the text pid is %04x", program.textPid);
2303                 tpid = program.textPid;
2304         }
2305
2306         if (!m_decoder)
2307         {
2308                 h.getDecodeDemux(m_decode_demux);
2309                 if (m_decode_demux)
2310                 {
2311                         m_decode_demux->getMPEGDecoder(m_decoder, m_is_primary);
2312                         if (m_decoder)
2313                                 m_decoder->connectVideoEvent(slot(*this, &eDVBServicePlay::video_event), m_video_event_connection);
2314                 }
2315                 if (m_decode_demux && m_is_primary)
2316                 {
2317                         m_teletext_parser = new eDVBTeletextParser(m_decode_demux);
2318                         m_teletext_parser->connectNewPage(slot(*this, &eDVBServicePlay::newSubtitlePage), m_new_subtitle_page_connection);
2319                         m_subtitle_parser = new eDVBSubtitleParser(m_decode_demux);
2320                         m_subtitle_parser->connectNewPage(slot(*this, &eDVBServicePlay::newDVBSubtitlePage), m_new_dvb_subtitle_page_connection);
2321                 } else
2322                 {
2323                         m_teletext_parser = 0;
2324                         m_subtitle_parser = 0;
2325                 }
2326
2327                 if (m_cue)
2328                         m_cue->setDecodingDemux(m_decode_demux, m_decoder);
2329         }
2330
2331         if (m_decoder)
2332         {
2333                 if (m_dvb_service)
2334                 {
2335                         achannel = m_dvb_service->getCacheEntry(eDVBService::cACHANNEL);
2336                         ac3_delay = m_dvb_service->getCacheEntry(eDVBService::cAC3DELAY);
2337                         pcm_delay = m_dvb_service->getCacheEntry(eDVBService::cPCMDELAY);
2338                 }
2339                 else // subservice
2340                 {
2341                         eServiceReferenceDVB ref;
2342                         m_service_handler.getServiceReference(ref);
2343                         eServiceReferenceDVB parent = ref.getParentServiceReference();
2344                         if (!parent)
2345                                 parent = ref;
2346                         if (parent)
2347                         {
2348                                 ePtr<eDVBResourceManager> res_mgr;
2349                                 if (!eDVBResourceManager::getInstance(res_mgr))
2350                                 {
2351                                         ePtr<iDVBChannelList> db;
2352                                         if (!res_mgr->getChannelList(db))
2353                                         {
2354                                                 ePtr<eDVBService> origService;
2355                                                 if (!db->getService(parent, origService))
2356                                                 {
2357                                                         ac3_delay = origService->getCacheEntry(eDVBService::cAC3DELAY);
2358                                                         pcm_delay = origService->getCacheEntry(eDVBService::cPCMDELAY);
2359                                                 }
2360                                         }
2361                                 }
2362                         }
2363                 }
2364
2365                 std::string config_delay;
2366                 int config_delay_int = 0;
2367                 if(ePythonConfigQuery::getConfigValue("config.av.generalAC3delay", config_delay) == 0)
2368                         config_delay_int = atoi(config_delay.c_str());
2369                 m_decoder->setAC3Delay(ac3_delay == -1 ? config_delay_int : ac3_delay + config_delay_int);
2370
2371                 if(ePythonConfigQuery::getConfigValue("config.av.generalPCMdelay", config_delay) == 0)
2372                         config_delay_int = atoi(config_delay.c_str());
2373                 else
2374                         config_delay_int = 0;
2375                 m_decoder->setPCMDelay(pcm_delay == -1 ? config_delay_int : pcm_delay + config_delay_int);
2376
2377                 m_decoder->setVideoPID(vpid, vpidtype);
2378                 selectAudioStream();
2379
2380                 if (!(m_is_pvr || m_timeshift_active || !m_is_primary))
2381                         m_decoder->setSyncPCR(pcrpid);
2382                 else
2383                         m_decoder->setSyncPCR(-1);
2384
2385                 if (m_is_primary)
2386                 {
2387                         m_decoder->setTextPID(tpid);
2388                         m_teletext_parser->start(program.textPid);
2389                 }
2390
2391                 if (vpid > 0 && vpid < 0x2000)
2392                         ;
2393                 else
2394                 {
2395                         std::string radio_pic;
2396                         if (!ePythonConfigQuery::getConfigValue("config.misc.radiopic", radio_pic))
2397                                 m_decoder->setRadioPic(radio_pic);
2398                 }
2399
2400 /*              if (!m_is_primary)
2401                         m_decoder->setTrickmode();
2402                 else */ if (m_is_paused)
2403                         m_decoder->pause();
2404                 else
2405                         m_decoder->play();
2406
2407                 m_decoder->setAudioChannel(achannel);
2408
2409                 /* don't worry about non-existing services, nor pvr services */
2410                 if (m_dvb_service)
2411                 {
2412                                 /* (audio pid will be set in selectAudioTrack */
2413                         m_dvb_service->setCacheEntry(eDVBService::cVPID, vpid);
2414                         m_dvb_service->setCacheEntry(eDVBService::cVTYPE, vpidtype == eDVBVideo::MPEG2 ? -1 : vpidtype);
2415                         m_dvb_service->setCacheEntry(eDVBService::cPCRPID, pcrpid);
2416                         m_dvb_service->setCacheEntry(eDVBService::cTPID, tpid);
2417                 }
2418         }
2419         m_have_video_pid = (vpid > 0 && vpid < 0x2000);
2420 }
2421
2422 void eDVBServicePlay::loadCuesheet()
2423 {
2424         std::string filename = m_reference.path + ".cuts";
2425         
2426         m_cue_entries.clear();
2427
2428         FILE *f = fopen(filename.c_str(), "rb");
2429
2430         if (f)
2431         {
2432                 eDebug("loading cuts..");
2433                 while (1)
2434                 {
2435                         unsigned long long where;
2436                         unsigned int what;
2437                         
2438                         if (!fread(&where, sizeof(where), 1, f))
2439                                 break;
2440                         if (!fread(&what, sizeof(what), 1, f))
2441                                 break;
2442                         
2443 #if BYTE_ORDER == LITTLE_ENDIAN
2444                         where = bswap_64(where);
2445 #endif
2446                         what = ntohl(what);
2447                         
2448                         if (what > 3)
2449                                 break;
2450                         
2451                         m_cue_entries.insert(cueEntry(where, what));
2452                 }
2453                 fclose(f);
2454                 eDebug("%d entries", m_cue_entries.size());
2455         } else
2456                 eDebug("cutfile not found!");
2457         
2458         m_cuesheet_changed = 0;
2459         cutlistToCuesheet();
2460         m_event((iPlayableService*)this, evCuesheetChanged);
2461 }
2462
2463 void eDVBServicePlay::saveCuesheet()
2464 {
2465         std::string filename = m_reference.path + ".cuts";
2466         
2467         FILE *f = fopen(filename.c_str(), "wb");
2468
2469         if (f)
2470         {
2471                 unsigned long long where;
2472                 int what;
2473
2474                 for (std::multiset<cueEntry>::iterator i(m_cue_entries.begin()); i != m_cue_entries.end(); ++i)
2475                 {
2476 #if BYTE_ORDER == BIG_ENDIAN
2477                         where = i->where;
2478 #else
2479                         where = bswap_64(i->where);
2480 #endif
2481                         what = htonl(i->what);
2482                         fwrite(&where, sizeof(where), 1, f);
2483                         fwrite(&what, sizeof(what), 1, f);
2484                         
2485                 }
2486                 fclose(f);
2487         }
2488         
2489         m_cuesheet_changed = 0;
2490 }
2491
2492 void eDVBServicePlay::cutlistToCuesheet()
2493 {
2494         if (!m_cue)
2495         {
2496                 eDebug("no cue sheet");
2497                 return;
2498         }       
2499         m_cue->clear();
2500         
2501         if (!m_cutlist_enabled)
2502         {
2503                 m_cue->commitSpans();
2504                 eDebug("cutlists were disabled");
2505                 return;
2506         }
2507
2508         pts_t in = 0, out = 0, length = 0;
2509         
2510         getLength(length);
2511                 
2512         std::multiset<cueEntry>::iterator i(m_cue_entries.begin());
2513         
2514         int have_any_span = 0;
2515         
2516         while (1)
2517         {
2518                 if (i == m_cue_entries.end())
2519                 {
2520                         if (!have_any_span)
2521                                 break;
2522                         out = length;
2523                 } else {
2524                         if (i->what == 0) /* in */
2525                         {
2526                                 in = i++->where;
2527                                 continue;
2528                         } else if (i->what == 1) /* out */
2529                                 out = i++->where;
2530                         else /* mark (2) or last play position (3) */
2531                         {
2532                                 i++;
2533                                 continue;
2534                         }
2535                 }
2536                 
2537                 if (in < 0)
2538                         in = 0;
2539                 if (out < 0)
2540                         out = 0;
2541                 if (in > length)
2542                         in = length;
2543                 if (out > length)
2544                         out = length;
2545                 
2546                 if (in < out)
2547                 {
2548                         have_any_span = 1;
2549                         m_cue->addSourceSpan(in, out);
2550                 }
2551                 
2552                 in = length;
2553                 
2554                 if (i == m_cue_entries.end())
2555                         break;
2556         }
2557         m_cue->commitSpans();
2558 }
2559
2560 RESULT eDVBServicePlay::enableSubtitles(eWidget *parent, ePyObject tuple)
2561 {
2562         if (m_subtitle_widget)
2563                 disableSubtitles(parent);
2564
2565         ePyObject entry;
2566         int tuplesize = PyTuple_Size(tuple);
2567         int type = 0;
2568
2569         if (!PyTuple_Check(tuple))
2570                 goto error_out;
2571
2572         if (tuplesize < 1)
2573                 goto error_out;
2574
2575         entry = PyTuple_GET_ITEM(tuple, 0);
2576
2577         if (!PyInt_Check(entry))
2578                 goto error_out;
2579
2580         type = PyInt_AsLong(entry);
2581
2582         if (type == 1)  // teletext subtitles
2583         {
2584                 int page, magazine, pid;
2585                 if (tuplesize < 4)
2586                         goto error_out;
2587
2588                 if (!m_teletext_parser)
2589                 {
2590                         eDebug("enable teletext subtitles.. no parser !!!");
2591                         return -1;
2592                 }
2593
2594                 entry = PyTuple_GET_ITEM(tuple, 1);
2595                 if (!PyInt_Check(entry))
2596                         goto error_out;
2597                 pid = PyInt_AsLong(entry);
2598
2599                 entry = PyTuple_GET_ITEM(tuple, 2);
2600                 if (!PyInt_Check(entry))
2601                         goto error_out;
2602                 page = PyInt_AsLong(entry);
2603
2604                 entry = PyTuple_GET_ITEM(tuple, 3);
2605                 if (!PyInt_Check(entry))
2606                         goto error_out;
2607                 magazine = PyInt_AsLong(entry);
2608
2609                 m_subtitle_widget = new eSubtitleWidget(parent);
2610                 m_subtitle_widget->resize(parent->size()); /* full size */
2611                 m_teletext_parser->setPageAndMagazine(page, magazine);
2612                 if (m_dvb_service)
2613                         m_dvb_service->setCacheEntry(eDVBService::cSUBTITLE,((pid&0xFFFF)<<16)|((page&0xFF)<<8)|(magazine&0xFF));
2614         }
2615         else if (type == 0)
2616         {
2617                 int pid = 0, composition_page_id = 0, ancillary_page_id = 0;
2618                 if (!m_subtitle_parser)
2619                 {
2620                         eDebug("enable dvb subtitles.. no parser !!!");
2621                         return -1;
2622                 }
2623                 if (tuplesize < 4)
2624                         goto error_out;
2625
2626                 entry = PyTuple_GET_ITEM(tuple, 1);
2627                 if (!PyInt_Check(entry))
2628                         goto error_out;
2629                 pid = PyInt_AsLong(entry);
2630
2631                 entry = PyTuple_GET_ITEM(tuple, 2);
2632                 if (!PyInt_Check(entry))
2633                         goto error_out;
2634                 composition_page_id = PyInt_AsLong(entry);
2635
2636                 entry = PyTuple_GET_ITEM(tuple, 3);
2637                 if (!PyInt_Check(entry))
2638                         goto error_out;
2639                 ancillary_page_id = PyInt_AsLong(entry);
2640
2641                 m_subtitle_widget = new eSubtitleWidget(parent);
2642                 m_subtitle_widget->resize(parent->size()); /* full size */
2643                 m_subtitle_parser->start(pid, composition_page_id, ancillary_page_id);
2644                 if (m_dvb_service)
2645                         m_dvb_service->setCacheEntry(eDVBService::cSUBTITLE, ((pid&0xFFFF)<<16)|((composition_page_id&0xFF)<<8)|(ancillary_page_id&0xFF));
2646         }
2647         else
2648                 goto error_out;
2649         return 0;
2650 error_out:
2651         eDebug("enableSubtitles needs a tuple as 2nd argument!\n"
2652                 "for teletext subtitles (0, pid, teletext_page, teletext_magazine)\n"
2653                 "for dvb subtitles (1, pid, composition_page_id, ancillary_page_id)");
2654         return -1;
2655 }
2656
2657 RESULT eDVBServicePlay::disableSubtitles(eWidget *parent)
2658 {
2659         delete m_subtitle_widget;
2660         m_subtitle_widget = 0;
2661         if (m_subtitle_parser)
2662         {
2663                 m_subtitle_parser->stop();
2664                 m_dvb_subtitle_pages.clear();
2665         }
2666         if (m_teletext_parser)
2667         {
2668                 m_teletext_parser->setPageAndMagazine(-1, -1);
2669                 m_subtitle_pages.clear();
2670         }
2671         if (m_dvb_service)
2672                 m_dvb_service->setCacheEntry(eDVBService::cSUBTITLE, -1);
2673         return 0;
2674 }
2675
2676 PyObject *eDVBServicePlay::getCachedSubtitle()
2677 {
2678         if (m_dvb_service)
2679         {
2680                 int tmp = m_dvb_service->getCacheEntry(eDVBService::cSUBTITLE);
2681                 if (tmp != -1)
2682                 {
2683                         unsigned int data = (unsigned int)tmp;
2684                         int pid = (data&0xFFFF0000)>>16;
2685                         ePyObject tuple = PyTuple_New(4);
2686                         eDVBServicePMTHandler::program program;
2687                         eDVBServicePMTHandler &h = m_timeshift_active ? m_service_handler_timeshift : m_service_handler;
2688                         if (!h.getProgramInfo(program))
2689                         {
2690                                 if (program.textPid==pid) // teletext
2691                                         PyTuple_SET_ITEM(tuple, 0, PyInt_FromLong(1)); // type teletext
2692                                 else
2693                                         PyTuple_SET_ITEM(tuple, 0, PyInt_FromLong(0)); // type dvb
2694                                 PyTuple_SET_ITEM(tuple, 1, PyInt_FromLong((data&0xFFFF0000)>>16)); // pid
2695                                 PyTuple_SET_ITEM(tuple, 2, PyInt_FromLong((data&0xFF00)>>8)); // composition_page / page
2696                                 PyTuple_SET_ITEM(tuple, 3, PyInt_FromLong(data&0xFF)); // ancillary_page / magazine
2697                                 return tuple;
2698                         }
2699                 }
2700         }
2701         Py_RETURN_NONE;
2702 }
2703
2704 PyObject *eDVBServicePlay::getSubtitleList()
2705 {
2706         if (!m_teletext_parser)
2707                 Py_RETURN_NONE;
2708         
2709         ePyObject l = PyList_New(0);
2710         std::set<int> added_ttx_pages;
2711
2712         std::set<eDVBServicePMTHandler::subtitleStream> &subs =
2713                 m_teletext_parser->m_found_subtitle_pages;
2714
2715         eDVBServicePMTHandler &h = m_timeshift_active ? m_service_handler_timeshift : m_service_handler;
2716         eDVBServicePMTHandler::program program;
2717         if (h.getProgramInfo(program))
2718                 eDebug("getting program info failed.");
2719         else
2720         {
2721                 for (std::vector<eDVBServicePMTHandler::subtitleStream>::iterator it(program.subtitleStreams.begin());
2722                         it != program.subtitleStreams.end(); ++it)
2723                 {
2724                         switch(it->subtitling_type)
2725                         {
2726                                 case 0x01: // ebu teletext subtitles
2727                                 {
2728                                         int page_number = it->teletext_page_number & 0xFF;
2729                                         int magazine_number = it->teletext_magazine_number & 7;
2730                                         int hash = magazine_number << 8 | page_number;
2731                                         if (added_ttx_pages.find(hash) == added_ttx_pages.end())
2732                                         {
2733                                                 ePyObject tuple = PyTuple_New(5);
2734                                                 PyTuple_SET_ITEM(tuple, 0, PyInt_FromLong(1));
2735                                                 PyTuple_SET_ITEM(tuple, 1, PyInt_FromLong(it->pid));
2736                                                 PyTuple_SET_ITEM(tuple, 2, PyInt_FromLong(page_number));
2737                                                 PyTuple_SET_ITEM(tuple, 3, PyInt_FromLong(magazine_number));
2738                                                 PyTuple_SET_ITEM(tuple, 4, PyString_FromString(it->language_code.c_str()));
2739                                                 PyList_Append(l, tuple);
2740                                                 Py_DECREF(tuple);
2741                                                 added_ttx_pages.insert(hash);
2742                                         }
2743                                         break;
2744                                 }
2745                                 case 0x10 ... 0x13:
2746                                 case 0x20 ... 0x23: // dvb subtitles
2747                                 {
2748                                         ePyObject tuple = PyTuple_New(5);
2749                                         PyTuple_SET_ITEM(tuple, 0, PyInt_FromLong(0));
2750                                         PyTuple_SET_ITEM(tuple, 1, PyInt_FromLong(it->pid));
2751                                         PyTuple_SET_ITEM(tuple, 2, PyInt_FromLong(it->composition_page_id));
2752                                         PyTuple_SET_ITEM(tuple, 3, PyInt_FromLong(it->ancillary_page_id));
2753                                         PyTuple_SET_ITEM(tuple, 4, PyString_FromString(it->language_code.c_str()));
2754                                         PyList_Insert(l, 0, tuple);
2755                                         Py_DECREF(tuple);
2756                                         break;
2757                                 }
2758                         }
2759                 }
2760         }
2761
2762         for (std::set<eDVBServicePMTHandler::subtitleStream>::iterator it(subs.begin());
2763                 it != subs.end(); ++it)
2764         {
2765                 int page_number = it->teletext_page_number & 0xFF;
2766                 int magazine_number = it->teletext_magazine_number & 7;
2767                 int hash = magazine_number << 8 | page_number;
2768                 if (added_ttx_pages.find(hash) == added_ttx_pages.end())
2769                 {
2770                         ePyObject tuple = PyTuple_New(5);
2771                         PyTuple_SET_ITEM(tuple, 0, PyInt_FromLong(1));
2772                         PyTuple_SET_ITEM(tuple, 1, PyInt_FromLong(it->pid));
2773                         PyTuple_SET_ITEM(tuple, 2, PyInt_FromLong(page_number));
2774                         PyTuple_SET_ITEM(tuple, 3, PyInt_FromLong(magazine_number));
2775                         PyTuple_SET_ITEM(tuple, 4, PyString_FromString("und"));  // undetermined
2776                         PyList_Append(l, tuple);
2777                         Py_DECREF(tuple);
2778                 }
2779         }
2780
2781         return l;
2782 }
2783
2784 void eDVBServicePlay::newSubtitlePage(const eDVBTeletextSubtitlePage &page)
2785 {
2786         if (m_subtitle_widget)
2787         {
2788                 pts_t pos = 0;
2789                 if (m_decoder)
2790                         m_decoder->getPTS(0, pos);
2791                 eDebug("got new subtitle page %lld %lld %d", pos, page.m_pts, page.m_have_pts);
2792                 m_subtitle_pages.push_back(page);
2793                 checkSubtitleTiming();
2794         }
2795 }
2796
2797 void eDVBServicePlay::checkSubtitleTiming()
2798 {
2799         eDebug("checkSubtitleTiming");
2800         if (!m_subtitle_widget)
2801                 return;
2802         while (1)
2803         {
2804                 enum { TELETEXT, DVB } type;
2805                 eDVBTeletextSubtitlePage page;
2806                 eDVBSubtitlePage dvb_page;
2807                 pts_t show_time;
2808                 if (!m_subtitle_pages.empty())
2809                 {
2810                         page = m_subtitle_pages.front();
2811                         type = TELETEXT;
2812                         show_time = page.m_pts;
2813                 }
2814                 else if (!m_dvb_subtitle_pages.empty())
2815                 {
2816                         dvb_page = m_dvb_subtitle_pages.front();
2817                         type = DVB;
2818                         show_time = dvb_page.m_show_time;
2819                 }
2820                 else
2821                         return;
2822         
2823                 pts_t pos = 0;
2824         
2825                 if (m_decoder)
2826                         m_decoder->getPTS(0, pos);
2827
2828                 eDebug("%lld %lld", pos, show_time);
2829                 int diff =  show_time - pos;
2830                 if (diff < 0)
2831                 {
2832                         eDebug("[late (%d ms)]", -diff / 90);
2833                         diff = 0;
2834                 }
2835 //              if (diff > 900000)
2836 //              {
2837 //                      eDebug("[invalid]");
2838 //                      diff = 0;
2839 //              }
2840         
2841                 if ((diff/90)<20)
2842                 {
2843                         if (type == TELETEXT)
2844                         {
2845                                 eDebug("display teletext subtitle page %lld", show_time);
2846                                 m_subtitle_widget->setPage(page);
2847                                 m_subtitle_pages.pop_front();
2848                         }
2849                         else
2850                         {
2851                                 eDebug("display dvb subtitle Page %lld", show_time);
2852                                 m_subtitle_widget->setPage(dvb_page);
2853                                 m_dvb_subtitle_pages.pop_front();
2854                         }
2855                 } else
2856                 {
2857                         eDebug("start subtitle delay %d", diff / 90);
2858                         m_subtitle_sync_timer->start(diff / 90, 1);
2859                         break;
2860                 }
2861         }
2862 }
2863
2864 void eDVBServicePlay::newDVBSubtitlePage(const eDVBSubtitlePage &p)
2865 {
2866         if (m_subtitle_widget)
2867         {
2868                 pts_t pos = 0;
2869                 if (m_decoder)
2870                         m_decoder->getPTS(0, pos);
2871                 eDebug("got new subtitle page %lld %lld", pos, p.m_show_time);
2872                 m_dvb_subtitle_pages.push_back(p);
2873                 checkSubtitleTiming();
2874         }
2875 }
2876
2877 int eDVBServicePlay::getAC3Delay()
2878 {
2879         if (m_dvb_service)
2880                 return m_dvb_service->getCacheEntry(eDVBService::cAC3DELAY);
2881         else if (m_decoder)
2882                 return m_decoder->getAC3Delay();
2883         else
2884                 return 0;
2885 }
2886
2887 int eDVBServicePlay::getPCMDelay()
2888 {
2889         if (m_dvb_service)
2890                 return m_dvb_service->getCacheEntry(eDVBService::cPCMDELAY);
2891         else if (m_decoder)
2892                 return m_decoder->getPCMDelay();
2893         else
2894                 return 0;
2895 }
2896
2897 void eDVBServicePlay::setAC3Delay(int delay)
2898 {
2899         if (m_dvb_service)
2900                 m_dvb_service->setCacheEntry(eDVBService::cAC3DELAY, delay ? delay : -1);
2901         if (m_decoder)
2902                 m_decoder->setAC3Delay(delay);
2903 }
2904
2905 void eDVBServicePlay::setPCMDelay(int delay)
2906 {
2907         if (m_dvb_service)
2908                 m_dvb_service->setCacheEntry(eDVBService::cPCMDELAY, delay ? delay : -1);
2909         if (m_decoder)
2910                 m_decoder->setPCMDelay(delay);
2911 }
2912
2913 void eDVBServicePlay::video_event(struct iTSMPEGDecoder::videoEvent event)
2914 {
2915         switch(event.type) {
2916                 case iTSMPEGDecoder::videoEvent::eventSizeChanged:
2917                         m_event((iPlayableService*)this, evVideoSizeChanged);
2918                         break;
2919                 case iTSMPEGDecoder::videoEvent::eventFrameRateChanged:
2920                         m_event((iPlayableService*)this, evVideoFramerateChanged);
2921                         break;
2922                 case iTSMPEGDecoder::videoEvent::eventProgressiveChanged:
2923                         m_event((iPlayableService*)this, evVideoProgressiveChanged);
2924                         break;
2925                 default:
2926                         break;
2927         }
2928 }
2929
2930 RESULT eDVBServicePlay::stream(ePtr<iStreamableService> &ptr)
2931 {
2932         ptr = this;
2933         return 0;
2934 }
2935
2936 PyObject *eDVBServicePlay::getStreamingData()
2937 {
2938         eDVBServicePMTHandler::program program;
2939         if (m_service_handler.getProgramInfo(program))
2940         {
2941                 Py_RETURN_NONE;
2942         }
2943
2944         ePyObject r = program.createPythonObject();
2945         ePtr<iDVBDemux> demux;
2946         if (!m_service_handler.getDataDemux(demux))
2947         {
2948                 uint8_t demux_id;
2949                 if (!demux->getCADemuxID(demux_id))
2950                         PutToDict(r, "demux", demux_id);
2951         }
2952
2953         return r;
2954 }
2955
2956
2957 DEFINE_REF(eDVBServicePlay)
2958
2959 PyObject *eDVBService::getInfoObject(const eServiceReference &ref, int w)
2960 {
2961         switch (w)
2962         {
2963         case iServiceInformation::sTransponderData:
2964                 return eStaticServiceDVBInformation().getInfoObject(ref, w);
2965         default:
2966                 break;
2967         }
2968         return iStaticServiceInformation::getInfoObject(ref, w);
2969 }
2970
2971 eAutoInitPtr<eServiceFactoryDVB> init_eServiceFactoryDVB(eAutoInitNumbers::service+1, "eServiceFactoryDVB");