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