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