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