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