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