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