speedup resolveFilename a bit
[enigma2.git] / lib / dvb / dvb.cpp
1 #include <lib/base/eerror.h>
2 #include <lib/base/filepush.h>
3 #include <lib/dvb/idvb.h>
4 #include <lib/dvb/dvb.h>
5 #include <lib/dvb/pmt.h>
6 #include <lib/dvb/sec.h>
7
8 #include <errno.h>
9 #include <sys/types.h>
10 #include <sys/stat.h>
11 #include <unistd.h>
12 #include <fcntl.h>
13 #include <sys/ioctl.h>
14
15 DEFINE_REF(eDVBRegisteredFrontend);
16 DEFINE_REF(eDVBRegisteredDemux);
17
18 DEFINE_REF(eDVBAllocatedFrontend);
19
20 eDVBAllocatedFrontend::eDVBAllocatedFrontend(eDVBRegisteredFrontend *fe): m_fe(fe)
21 {
22         m_fe->inc_use();
23 }
24
25 eDVBAllocatedFrontend::~eDVBAllocatedFrontend()
26 {
27         m_fe->dec_use();
28 }
29
30 DEFINE_REF(eDVBAllocatedDemux);
31
32 eDVBAllocatedDemux::eDVBAllocatedDemux(eDVBRegisteredDemux *demux): m_demux(demux)
33 {
34         m_demux->m_inuse++;
35 }
36
37 eDVBAllocatedDemux::~eDVBAllocatedDemux()
38 {
39         --m_demux->m_inuse;
40 }
41
42 DEFINE_REF(eDVBResourceManager);
43
44 eDVBResourceManager *eDVBResourceManager::instance;
45
46 RESULT eDVBResourceManager::getInstance(ePtr<eDVBResourceManager> &ptr)
47 {
48         if (instance)
49         {
50                 ptr = instance;
51                 return 0;
52         }
53         return -1;
54 }
55
56 ePtr<eDVBResourceManager> NewResourceManagerPtr(void)
57 {
58         ePtr<eDVBResourceManager> ptr;
59         eDVBResourceManager::getInstance(ptr);
60         return ptr;
61 }
62
63 eDVBResourceManager::eDVBResourceManager()
64         :m_releaseCachedChannelTimer(eApp)
65 {
66         avail = 1;
67         busy = 0;
68         m_sec = new eDVBSatelliteEquipmentControl(m_frontend);
69         if (!instance)
70                 instance = this;
71                 
72                 /* search available adapters... */
73
74                 // add linux devices
75         
76         int num_adapter = 0;
77         while (eDVBAdapterLinux::exist(num_adapter))
78         {
79                 addAdapter(new eDVBAdapterLinux(num_adapter));
80                 num_adapter++;
81         }
82         
83         eDebug("found %d adapter, %d frontends and %d demux", 
84                 m_adapter.size(), m_frontend.size(), m_demux.size());
85
86         eDVBCAService::registerChannelCallback(this);
87
88         CONNECT(m_releaseCachedChannelTimer.timeout, eDVBResourceManager::releaseCachedChannel);
89 }
90
91 void eDVBResourceManager::feStateChanged()
92 {
93         int mask=0;
94         for (eSmartPtrList<eDVBRegisteredFrontend>::iterator i(m_frontend.begin()); i != m_frontend.end(); ++i)
95                 if (i->m_inuse)
96                         mask |= ( 1 << i->m_frontend->getSlotID() );
97         /* emit */ frontendUseMaskChanged(mask);
98 }
99
100 DEFINE_REF(eDVBAdapterLinux);
101 eDVBAdapterLinux::eDVBAdapterLinux(int nr): m_nr(nr)
102 {
103                 // scan frontends
104         int num_fe = 0;
105         
106         eDebug("scanning for frontends..");
107         while (1)
108         {
109                 struct stat s;
110                 char filename[128];
111 #if HAVE_DVB_API_VERSION < 3
112                 sprintf(filename, "/dev/dvb/card%d/frontend%d", m_nr, num_fe);
113 #else
114                 sprintf(filename, "/dev/dvb/adapter%d/frontend%d", m_nr, num_fe);
115 #endif
116                 if (stat(filename, &s))
117                         break;
118                 ePtr<eDVBFrontend> fe;
119
120                 int ok = 0;
121                 fe = new eDVBFrontend(m_nr, num_fe, ok);
122                 if (ok)
123                         m_frontend.push_back(fe);
124                 ++num_fe;
125         }
126         
127                 // scan demux
128         int num_demux = 0;
129         while (1)
130         {
131                 struct stat s;
132                 char filename[128];
133 #if HAVE_DVB_API_VERSION < 3
134                 sprintf(filename, "/dev/dvb/card%d/demux%d", m_nr, num_demux);
135 #else
136                 sprintf(filename, "/dev/dvb/adapter%d/demux%d", m_nr, num_demux);
137 #endif
138                 if (stat(filename, &s))
139                         break;
140                 ePtr<eDVBDemux> demux;
141                 
142                 demux = new eDVBDemux(m_nr, num_demux);
143                 m_demux.push_back(demux);
144                         
145                 ++num_demux;
146         }
147 }
148
149 int eDVBAdapterLinux::getNumDemux()
150 {
151         return m_demux.size();
152 }
153
154 RESULT eDVBAdapterLinux::getDemux(ePtr<eDVBDemux> &demux, int nr)
155 {
156         eSmartPtrList<eDVBDemux>::iterator i(m_demux.begin());
157         while (nr && (i != m_demux.end()))
158         {
159                 --nr;
160                 ++i;
161         }
162         
163         if (i != m_demux.end())
164                 demux = *i;
165         else
166                 return -1;
167                 
168         return 0;
169 }
170
171 int eDVBAdapterLinux::getNumFrontends()
172 {
173         return m_frontend.size();
174 }
175
176 RESULT eDVBAdapterLinux::getFrontend(ePtr<eDVBFrontend> &fe, int nr)
177 {
178         eSmartPtrList<eDVBFrontend>::iterator i(m_frontend.begin());
179         while (nr && (i != m_frontend.end()))
180         {
181                 --nr;
182                 ++i;
183         }
184         
185         if (i != m_frontend.end())
186                 fe = *i;
187         else
188                 return -1;
189                 
190         return 0;
191 }
192
193 int eDVBAdapterLinux::exist(int nr)
194 {
195         struct stat s;
196         char filename[128];
197 #if HAVE_DVB_API_VERSION < 3
198         sprintf(filename, "/dev/dvb/card%d", nr);
199 #else
200         sprintf(filename, "/dev/dvb/adapter%d", nr);
201 #endif
202         if (!stat(filename, &s))
203                 return 1;
204         return 0;
205 }
206
207 eDVBResourceManager::~eDVBResourceManager()
208 {
209         if (instance == this)
210                 instance = 0;
211 }
212
213 void eDVBResourceManager::addAdapter(iDVBAdapter *adapter)
214 {
215         int num_fe = adapter->getNumFrontends();
216         int num_demux = adapter->getNumDemux();
217         
218         m_adapter.push_back(adapter);
219         
220         int i;
221         for (i=0; i<num_demux; ++i)
222         {
223                 ePtr<eDVBDemux> demux;
224                 if (!adapter->getDemux(demux, i))
225                         m_demux.push_back(new eDVBRegisteredDemux(demux, adapter));
226         }
227
228         ePtr<eDVBRegisteredFrontend> prev_dvbt_frontend;
229         for (i=0; i<num_fe; ++i)
230         {
231                 ePtr<eDVBFrontend> frontend;
232                 if (!adapter->getFrontend(frontend, i))
233                 {
234                         int frontendType=0;
235                         frontend->getFrontendType(frontendType);
236                         eDVBRegisteredFrontend *new_fe = new eDVBRegisteredFrontend(frontend, adapter);
237                         CONNECT(new_fe->stateChanged, eDVBResourceManager::feStateChanged);
238                         m_frontend.push_back(new_fe);
239                         frontend->setSEC(m_sec);
240                         // we must link all dvb-t frontends ( for active antenna voltage )
241                         if (frontendType == iDVBFrontend::feTerrestrial)
242                         {
243                                 if (prev_dvbt_frontend)
244                                 {
245                                         prev_dvbt_frontend->m_frontend->setData(eDVBFrontend::LINKED_NEXT_PTR, (long)new_fe);
246                                         frontend->setData(eDVBFrontend::LINKED_PREV_PTR, (long)&(*prev_dvbt_frontend));
247                                 }
248                                 prev_dvbt_frontend = new_fe;
249                         }
250                 }
251         }
252 }
253
254 PyObject *eDVBResourceManager::setFrontendSlotInformations(ePyObject list)
255 {
256         if (!PyList_Check(list))
257         {
258                 PyErr_SetString(PyExc_StandardError, "eDVBResourceManager::setFrontendSlotInformations argument should be a python list");
259                 return NULL;
260         }
261         if ((unsigned int)PyList_Size(list) != m_frontend.size())
262         {
263                 char blasel[256];
264                 sprintf(blasel, "eDVBResourceManager::setFrontendSlotInformations list size incorrect %d frontends avail, but %d entries in slotlist",
265                         m_frontend.size(), PyList_Size(list));
266                 PyErr_SetString(PyExc_StandardError, blasel);
267                 return NULL;
268         }
269         int pos=0;
270         for (eSmartPtrList<eDVBRegisteredFrontend>::iterator i(m_frontend.begin()); i != m_frontend.end(); ++i)
271         {
272                 ePyObject obj = PyList_GET_ITEM(list, pos++);
273                 if (!i->m_frontend->setSlotInfo(obj))
274                         return NULL;
275         }
276         Py_RETURN_NONE;
277 }
278
279 RESULT eDVBResourceManager::allocateFrontend(ePtr<eDVBAllocatedFrontend> &fe, ePtr<iDVBFrontendParameters> &feparm)
280 {
281         ePtr<eDVBRegisteredFrontend> best;
282         int bestval = 0;
283         int foundone = 0;
284
285         for (eSmartPtrList<eDVBRegisteredFrontend>::iterator i(m_frontend.begin()); i != m_frontend.end(); ++i)
286         {
287                 int c = i->m_frontend->isCompatibleWith(feparm);
288
289                 if (c)  /* if we have at least one frontend which is compatible with the source, flag this. */
290                         foundone = 1;
291
292                 if (!i->m_inuse)
293                 {
294                         if (c > bestval)
295                         {
296                                 bestval = c;
297                                 best = i;
298                         }
299                 }
300         }
301
302         if (best)
303         {
304                 fe = new eDVBAllocatedFrontend(best);
305                 return 0;
306         }
307
308         fe = 0;
309
310         if (foundone)
311                 return errAllSourcesBusy;
312         else
313                 return errNoSourceFound;
314 }
315
316 RESULT eDVBResourceManager::allocateFrontendByIndex(ePtr<eDVBAllocatedFrontend> &fe, int slot_index)
317 {
318         int err = errNoSourceFound;
319         for (eSmartPtrList<eDVBRegisteredFrontend>::iterator i(m_frontend.begin()); i != m_frontend.end(); ++i)
320                 if (!i->m_inuse && i->m_frontend->getSlotID() == slot_index)
321                 {
322                         // check if another slot linked to this is in use
323                         eDVBRegisteredFrontend *satpos_depends_to_fe =
324                                 (eDVBRegisteredFrontend*) i->m_frontend->m_data[eDVBFrontend::SATPOS_DEPENDS_PTR];
325                         if ( (long)satpos_depends_to_fe != -1 )
326                         {
327                                 if (satpos_depends_to_fe->m_inuse)
328                                 {
329                                         eDebug("another satpos depending frontend is in use.. so allocateFrontendByIndex not possible!");
330                                         err = errAllSourcesBusy;
331                                         goto alloc_fe_by_id_not_possible;
332                                 }
333                         }
334                         else // check linked tuners
335                         {
336                                 eDVBRegisteredFrontend *next =
337                                         (eDVBRegisteredFrontend *) i->m_frontend->m_data[eDVBFrontend::LINKED_NEXT_PTR];
338                                 while ( (long)next != -1 )
339                                 {
340                                         if (next->m_inuse)
341                                         {
342                                                 eDebug("another linked frontend is in use.. so allocateFrontendByIndex not possible!");
343                                                 err = errAllSourcesBusy;
344                                                 goto alloc_fe_by_id_not_possible;
345                                         }
346                                         next = (eDVBRegisteredFrontend *)next->m_frontend->m_data[eDVBFrontend::LINKED_NEXT_PTR];
347                                 }
348                                 eDVBRegisteredFrontend *prev = (eDVBRegisteredFrontend *)
349                                         i->m_frontend->m_data[eDVBFrontend::LINKED_PREV_PTR];
350                                 while ( (long)prev != -1 )
351                                 {
352                                         if (prev->m_inuse)
353                                         {
354                                                 eDebug("another linked frontend is in use.. so allocateFrontendByIndex not possible!");
355                                                 err = errAllSourcesBusy;
356                                                 goto alloc_fe_by_id_not_possible;
357                                         }
358                                         prev = (eDVBRegisteredFrontend *)prev->m_frontend->m_data[eDVBFrontend::LINKED_PREV_PTR];
359                                 }
360                         }
361                         fe = new eDVBAllocatedFrontend(i);
362                         return 0;
363                 }
364 alloc_fe_by_id_not_possible:
365         fe = 0;
366         return err;
367 }
368
369 RESULT eDVBResourceManager::allocateDemux(eDVBRegisteredFrontend *fe, ePtr<eDVBAllocatedDemux> &demux, int cap)
370 {
371                 /* find first unused demux which is on same adapter as frontend (or any, if PVR)
372                    never use the first one unless we need a decoding demux. */
373
374         eDebug("allocate demux");
375         eSmartPtrList<eDVBRegisteredDemux>::iterator i(m_demux.begin());
376         
377         if (i == m_demux.end())
378                 return -1;
379                 
380         int n=0;
381                 /* FIXME: hardware demux policy */
382         if (!(cap & iDVBChannel::capDecode))
383         {
384                 if (m_demux.size() > 2)  /* assumed to be true, otherwise we have lost anyway */
385                 {
386                         ++i, ++n;
387                         ++i, ++n;
388                 }
389         }
390         
391         for (; i != m_demux.end(); ++i, ++n)
392         {
393                 int is_decode = n < 2;
394                 
395                 int in_use = is_decode ? (i->m_demux->getRefCount() != 2) : i->m_inuse;
396                 
397                 if ((!in_use) && ((!fe) || (i->m_adapter == fe->m_adapter)))
398                 {
399                         if ((cap & iDVBChannel::capDecode) && !is_decode)
400                                 continue;
401                         
402                         demux = new eDVBAllocatedDemux(i);
403                         if (fe)
404                                 demux->get().setSourceFrontend(fe->m_frontend->getDVBID());
405                         else
406                                 demux->get().setSourcePVR(0);
407                         return 0;
408                 }
409         }
410         eDebug("demux not found");
411         return -1;
412 }
413
414 RESULT eDVBResourceManager::setChannelList(iDVBChannelList *list)
415 {
416         m_list = list;
417         return 0;
418 }
419
420 RESULT eDVBResourceManager::getChannelList(ePtr<iDVBChannelList> &list)
421 {
422         list = m_list;
423         if (list)
424                 return 0;
425         else
426                 return -ENOENT;
427 }
428
429 RESULT eDVBResourceManager::allocateChannel(const eDVBChannelID &channelid, eUsePtr<iDVBChannel> &channel)
430 {
431                 /* first, check if a channel is already existing. */
432
433         if (m_cached_channel)
434         {
435                 eDVBChannel *cache_chan = (eDVBChannel*)&(*m_cached_channel);
436                 if(channelid==cache_chan->getChannelID())
437                 {
438                         eDebug("use cached_channel");
439                         channel = m_cached_channel;
440                         return 0;
441                 }
442                 m_cached_channel_state_changed_conn.disconnect();
443                 m_cached_channel=0;
444                 m_releaseCachedChannelTimer.stop();
445         }
446
447 //      eDebug("allocate channel.. %04x:%04x", channelid.transport_stream_id.get(), channelid.original_network_id.get());
448         for (std::list<active_channel>::iterator i(m_active_channels.begin()); i != m_active_channels.end(); ++i)
449         {
450 //              eDebug("available channel.. %04x:%04x", i->m_channel_id.transport_stream_id.get(), i->m_channel_id.original_network_id.get());
451                 if (i->m_channel_id == channelid)
452                 {
453 //                      eDebug("found shared channel..");
454                         channel = i->m_channel;
455                         return 0;
456                 }
457         }
458         
459         /* no currently available channel is tuned to this channelid. create a new one, if possible. */
460
461         if (!m_list)
462         {
463                 eDebug("no channel list set!");
464                 return errNoChannelList;
465         }
466
467         ePtr<iDVBFrontendParameters> feparm;
468         if (m_list->getChannelFrontendData(channelid, feparm))
469         {
470                 eDebug("channel not found!");
471                 return errChannelNotInList;
472         }
473
474         /* allocate a frontend. */
475         
476         ePtr<eDVBAllocatedFrontend> fe;
477
478         int err = allocateFrontend(fe, feparm);
479         if (err)
480                 return err;
481
482         RESULT res;
483         ePtr<eDVBChannel> ch;
484         ch = new eDVBChannel(this, fe);
485
486         res = ch->setChannel(channelid, feparm);
487         if (res)
488         {
489                 channel = 0;
490                 return errChidNotFound;
491         }
492         m_cached_channel = channel = ch;
493         m_cached_channel_state_changed_conn =
494                 CONNECT(ch->m_stateChanged,eDVBResourceManager::DVBChannelStateChanged);
495
496         return 0;
497 }
498
499 void eDVBResourceManager::DVBChannelStateChanged(iDVBChannel *chan)
500 {
501         int state=0;
502         chan->getState(state);
503         switch (state)
504         {
505                 case iDVBChannel::state_release:
506                 case iDVBChannel::state_ok:
507                 {
508                         eDebug("stop release channel timer");
509                         m_releaseCachedChannelTimer.stop();
510                         break;
511                 }
512                 case iDVBChannel::state_last_instance:
513                 {
514                         eDebug("start release channel timer");
515                         m_releaseCachedChannelTimer.start(3000, true);
516                         break;
517                 }
518                 default: // ignore all other events
519                         break;
520         }
521 }
522
523 void eDVBResourceManager::releaseCachedChannel()
524 {
525         eDebug("release cached channel (timer timeout)");
526         m_cached_channel=0;
527 }
528
529 RESULT eDVBResourceManager::allocateRawChannel(eUsePtr<iDVBChannel> &channel, int slot_index)
530 {
531         ePtr<eDVBAllocatedFrontend> fe;
532
533         if (m_cached_channel)
534         {
535                 m_cached_channel_state_changed_conn.disconnect();
536                 m_cached_channel=0;
537                 m_releaseCachedChannelTimer.stop();
538         }
539
540         int err = allocateFrontendByIndex(fe, slot_index);
541         if (err)
542                 return err;
543
544         eDVBChannel *ch;
545         ch = new eDVBChannel(this, fe);
546
547         channel = ch;
548         return 0;
549 }
550
551
552 RESULT eDVBResourceManager::allocatePVRChannel(eUsePtr<iDVBPVRChannel> &channel)
553 {
554         ePtr<eDVBAllocatedDemux> demux;
555
556         if (m_cached_channel && m_releaseCachedChannelTimer.isActive())
557         {
558                 m_cached_channel_state_changed_conn.disconnect();
559                 m_cached_channel=0;
560                 m_releaseCachedChannelTimer.stop();
561         }
562
563         eDVBChannel *ch;
564         ch = new eDVBChannel(this, 0);
565
566         channel = ch;
567         return 0;
568 }
569
570 RESULT eDVBResourceManager::addChannel(const eDVBChannelID &chid, eDVBChannel *ch)
571 {
572         m_active_channels.push_back(active_channel(chid, ch));
573         /* emit */ m_channelAdded(ch);
574         return 0;
575 }
576
577 RESULT eDVBResourceManager::removeChannel(eDVBChannel *ch)
578 {
579         int cnt = 0;
580         for (std::list<active_channel>::iterator i(m_active_channels.begin()); i != m_active_channels.end();)
581         {
582                 if (i->m_channel == ch)
583                 {
584                         i = m_active_channels.erase(i);
585                         ++cnt;
586                 } else
587                         ++i;
588         }
589         ASSERT(cnt == 1);
590         if (cnt == 1)
591                 return 0;
592         return -ENOENT;
593 }
594
595 RESULT eDVBResourceManager::connectChannelAdded(const Slot1<void,eDVBChannel*> &channelAdded, ePtr<eConnection> &connection)
596 {
597         connection = new eConnection((eDVBResourceManager*)this, m_channelAdded.connect(channelAdded));
598         return 0;
599 }
600
601 int eDVBResourceManager::canAllocateFrontend(ePtr<iDVBFrontendParameters> &feparm)
602 {
603         ePtr<eDVBRegisteredFrontend> best;
604         int bestval = 0;
605
606         for (eSmartPtrList<eDVBRegisteredFrontend>::iterator i(m_frontend.begin()); i != m_frontend.end(); ++i)
607                 if (!i->m_inuse)
608                 {
609                         int c = i->m_frontend->isCompatibleWith(feparm);
610                         if (c > bestval)
611                                 bestval = c;
612                 }
613         return bestval;
614 }
615
616 int tuner_type_channel_default(ePtr<iDVBChannelList> &channellist, const eDVBChannelID &chid)
617 {
618         if (channellist)
619         {
620                 ePtr<iDVBFrontendParameters> feparm;
621                 if (!channellist->getChannelFrontendData(chid, feparm))
622                 {
623                         int system;
624                         if (!feparm->getSystem(system))
625                         {
626                                 switch(system)
627                                 {
628                                         case iDVBFrontend::feSatellite:
629                                                 return 50000;
630                                         case iDVBFrontend::feCable:
631                                                 return 40000;
632                                         case iDVBFrontend::feTerrestrial:
633                                                 return 30000;
634                                         default:
635                                                 break;
636                                 }
637                         }
638                 }
639         }
640         return 0;
641 }
642
643 int eDVBResourceManager::canAllocateChannel(const eDVBChannelID &channelid, const eDVBChannelID& ignore)
644 {
645         int ret=0;
646         if (m_cached_channel)
647         {
648                 eDVBChannel *cache_chan = (eDVBChannel*)&(*m_cached_channel);
649                 if(channelid==cache_chan->getChannelID())
650                         return tuner_type_channel_default(m_list, channelid);
651         }
652
653                 /* first, check if a channel is already existing. */
654 //      eDebug("allocate channel.. %04x:%04x", channelid.transport_stream_id.get(), channelid.original_network_id.get());
655         for (std::list<active_channel>::iterator i(m_active_channels.begin()); i != m_active_channels.end(); ++i)
656         {
657 //              eDebug("available channel.. %04x:%04x", i->m_channel_id.transport_stream_id.get(), i->m_channel_id.original_network_id.get());
658                 if (i->m_channel_id == channelid)
659                 {
660 //                      eDebug("found shared channel..");
661                         return tuner_type_channel_default(m_list, channelid);
662                 }
663         }
664
665         int *decremented_cached_channel_fe_usecount=NULL,
666                 *decremented_fe_usecount=NULL;
667
668         for (std::list<active_channel>::iterator i(m_active_channels.begin()); i != m_active_channels.end(); ++i)
669         {
670 //              eDebug("available channel.. %04x:%04x", i->m_channel_id.transport_stream_id.get(), i->m_channel_id.original_network_id.get());
671                 if (i->m_channel_id == ignore)
672                 {
673                         eDVBChannel *channel = (eDVBChannel*) &(*i->m_channel);
674                         // one eUsePtr<iDVBChannel> is used in eDVBServicePMTHandler
675                         // another on eUsePtr<iDVBChannel> is used in the eDVBScan instance used in eDVBServicePMTHandler (for SDT scan)
676                         // so we must check here if usecount is 3 (when the channel is equal to the cached channel)
677                         // or 2 when the cached channel is not equal to the compared channel
678                         if (channel == &(*m_cached_channel) ? channel->getUseCount() == 3 : channel->getUseCount() == 2)  // channel only used once..
679                         {
680                                 ePtr<iDVBFrontend> fe;
681                                 if (!i->m_channel->getFrontend(fe))
682                                 {
683                                         for (eSmartPtrList<eDVBRegisteredFrontend>::iterator ii(m_frontend.begin()); ii != m_frontend.end(); ++ii)
684                                         {
685                                                 if ( &(*fe) == &(*ii->m_frontend) )
686                                                 {
687                                                         --ii->m_inuse;
688                                                         decremented_fe_usecount = &ii->m_inuse;
689                                                         if (channel == &(*m_cached_channel))
690                                                                 decremented_cached_channel_fe_usecount = decremented_fe_usecount;
691                                                         break;
692                                                 }
693                                         }
694                                 }
695                         }
696                         break;
697                 }
698         }
699
700         if (!decremented_cached_channel_fe_usecount)
701         {
702                 if (m_cached_channel)
703                 {
704                         eDVBChannel *channel = (eDVBChannel*) &(*m_cached_channel);
705                         if (channel->getUseCount() == 1)
706                         {
707                                 ePtr<iDVBFrontend> fe;
708                                 if (!channel->getFrontend(fe))
709                                 {
710                                         for (eSmartPtrList<eDVBRegisteredFrontend>::iterator ii(m_frontend.begin()); ii != m_frontend.end(); ++ii)
711                                         {
712                                                 if ( &(*fe) == &(*ii->m_frontend) )
713                                                 {
714                                                         --ii->m_inuse;
715                                                         decremented_cached_channel_fe_usecount = &ii->m_inuse;
716                                                         break;
717                                                 }
718                                         }
719                                 }
720                         }
721                 }
722         }
723         else
724                 decremented_cached_channel_fe_usecount=NULL;
725
726         ePtr<iDVBFrontendParameters> feparm;
727
728         if (!m_list)
729         {
730                 eDebug("no channel list set!");
731                 goto error;
732         }
733
734         if (m_list->getChannelFrontendData(channelid, feparm))
735         {
736                 eDebug("channel not found!");
737                 goto error;
738         }
739
740         ret = canAllocateFrontend(feparm);
741
742 error:
743         if (decremented_fe_usecount)
744                 ++(*decremented_fe_usecount);
745         if (decremented_cached_channel_fe_usecount)
746                 ++(*decremented_cached_channel_fe_usecount);
747
748         return ret;
749 }
750
751 class eDVBChannelFilePush: public eFilePushThread
752 {
753 public:
754         eDVBChannelFilePush() { setIFrameSearch(0); setTimebaseChange(0); }
755         void setIFrameSearch(int enabled) { m_iframe_search = enabled; m_iframe_state = 0; }
756
757                         /* "timebase change" is for doing trickmode playback at an exact speed, even when pictures are skipped. */
758                         /* you need to set it to 1/16 if you want 16x playback, for example. you need video master sync. */
759         void setTimebaseChange(int ratio) { m_timebase_change = ratio; } /* 16bit fixpoint, 0 for disable */
760 protected:
761         int m_iframe_search, m_iframe_state, m_pid;
762         int m_timebase_change;
763         int filterRecordData(const unsigned char *data, int len, size_t &current_span_remaining);
764 };
765
766 int eDVBChannelFilePush::filterRecordData(const unsigned char *_data, int len, size_t &current_span_remaining)
767 {
768 #if 0
769         if (m_timebase_change)
770         {
771                 eDebug("timebase change: %d", m_timebase_change);
772                 int offset;
773                 for (offset = 0; offset < len; offset += 188)
774                 {
775                         unsigned char *pkt = (unsigned char*)_data + offset;
776                         if (pkt[1] & 0x40) /* pusi */
777                         {
778                                 if (pkt[3] & 0x20) // adaption field present?
779                                         pkt += pkt[4] + 4 + 1;  /* skip adaption field and header */
780                                 else
781                                         pkt += 4; /* skip header */
782                                 if (pkt[0] || pkt[1] || (pkt[2] != 1))
783                                 {
784                                         eWarning("broken startcode");
785                                         continue;
786                                 }
787
788                                 pts_t pts = 0;
789
790                                 if (pkt[7] & 0x80) // PTS present?
791                                 {
792                                         pts  = ((unsigned long long)(pkt[ 9]&0xE))  << 29;
793                                         pts |= ((unsigned long long)(pkt[10]&0xFF)) << 22;
794                                         pts |= ((unsigned long long)(pkt[11]&0xFE)) << 14;
795                                         pts |= ((unsigned long long)(pkt[12]&0xFF)) << 7;
796                                         pts |= ((unsigned long long)(pkt[13]&0xFE)) >> 1;
797
798 #if 0
799                                         off_t off = 0;
800                                         RESULT r = m_tstools.fixupPTS(off, pts);
801                                         if (r)
802                                                 eWarning("fixup PTS while trickmode playback failed.\n");
803 #endif
804
805                                         int sec = pts / 90000;
806                                         int frm = pts % 90000;
807                                         int min = sec / 60;
808                                         sec %= 60;
809                                         int hr = min / 60;
810                                         min %= 60;
811                                         int d = hr / 24;
812                                         hr %= 24;
813
814 //                                      eDebug("original, fixed pts: %016llx %d:%02d:%02d:%02d:%05d", pts, d, hr, min, sec, frm);
815
816                                         pts += 0x80000000LL;
817                                         pts *= m_timebase_change;
818                                         pts >>= 16;
819
820                                         sec = pts / 90000;
821                                         frm = pts % 90000;
822                                         min = sec / 60;
823                                         sec %= 60;
824                                         hr = min / 60;
825                                         min %= 60;
826                                         d = hr / 24;
827                                         hr %= 24;
828
829 //                                      eDebug("new pts (after timebase change): %016llx %d:%02d:%02d:%02d:%05d", pts, d, hr, min, sec, frm);
830
831                                         pkt[9] &= ~0xE;
832                                         pkt[10] = 0;
833                                         pkt[11] &= ~1;
834                                         pkt[12] = 0;
835                                         pkt[13] &= ~1;
836
837                                         pkt[9]  |= (pts >> 29) & 0xE;
838                                         pkt[10] |= (pts >> 22) & 0xFF;
839                                         pkt[11] |= (pts >> 14) & 0xFE;
840                                         pkt[12] |= (pts >> 7) & 0xFF;
841                                         pkt[13] |= (pts << 1) & 0xFE;
842                                 }
843                         }
844                 }
845         }
846 #endif
847
848 #if 1 /* not yet */
849         if (!m_iframe_search)
850                 return len;
851
852         unsigned char *data = (unsigned char*)_data; /* remove that const. we know what we are doing. */
853
854 //      eDebug("filterRecordData, size=%d (mod 188=%d), first byte is %02x", len, len %188, data[0]);
855
856         unsigned char *d = data;
857         while ((d = (unsigned char*)memmem(d, data + len - d, "\x00\x00\x01", 3)))
858         {
859                 int offset = d - data;
860                 int ts_offset = offset - offset % 188; /* offset to the start of TS packet */
861                 unsigned char *ts = data + ts_offset;
862                 int pid = ((ts[1] << 8) | ts[2]) & 0x1FFF;
863
864                 if ((d[3] == 0) && (m_pid == pid))  /* picture start */
865                 {
866                         int picture_type = (d[5] >> 3) & 7;
867                         d += 4;
868
869 //                      eDebug("%d-frame at %d, offset in TS packet: %d, pid=%04x", picture_type, offset, offset % 188, pid);
870
871                         if (m_iframe_state == 1)
872                         {
873                                         /* we are allowing data, and stop allowing data on the next frame. 
874                                            we now found a frame. so stop here. */
875                                 memset(data + offset, 0, 188 - (offset%188)); /* zero out rest of TS packet */
876                                 current_span_remaining = 0;
877                                 m_iframe_state = 0;
878                                 unsigned char *fts = ts + 188;
879                                 while (fts < (data + len))
880                                 {
881                                         fts[1] |= 0x1f;
882                                         fts[2] |= 0xff; /* drop packet */
883                                         fts += 188;
884                                 }
885
886                                 return len; // ts_offset + 188; /* deliver this packet, but not more. */
887                         } else
888                         {
889                                 if (picture_type != 1) /* we are only interested in I frames */
890                                         continue;
891
892                                 unsigned char *fts = data;
893                                 while (fts < ts)
894                                 {
895                                         fts[1] |= 0x1f;
896                                         fts[2] |= 0xff; /* drop packet */
897
898                                         fts += 188;
899                                 }
900                                                 /* force payload only */
901                                 ts[3] &= ~0x30;
902                                 ts[3] |=  0x10;
903
904 //                              memset(ts + 4, 0xFF, (offset % 188) - 4);
905
906                                 m_iframe_state = 1;
907                         }
908                 } else if ((d[3] & 0xF0) == 0xE0) /* video stream */
909                 {
910                         if (m_pid != pid)
911                         {
912                                 eDebug("now locked to pid %04x", pid);
913                                 m_pid = pid;
914                         }
915 //                      m_pid = 0x6e;
916                         d += 4;
917                 } else
918                         d += 4; /* ignore */
919
920         }
921
922         if (m_iframe_state == 1)
923                 return len;
924         else
925                 return 0; /* we need find an iframe first */
926 #else
927         return len;
928 #endif
929 }
930
931 DEFINE_REF(eDVBChannel);
932
933 eDVBChannel::eDVBChannel(eDVBResourceManager *mgr, eDVBAllocatedFrontend *frontend): m_state(state_idle), m_mgr(mgr)
934 {
935         m_frontend = frontend;
936
937         m_pvr_thread = 0;
938         
939         m_skipmode_n = m_skipmode_m = 0;
940         
941         if (m_frontend)
942                 m_frontend->get().connectStateChange(slot(*this, &eDVBChannel::frontendStateChanged), m_conn_frontendStateChanged);
943 }
944
945 eDVBChannel::~eDVBChannel()
946 {
947         if (m_channel_id)
948                 m_mgr->removeChannel(this);
949
950         stopFile();
951 }
952
953 void eDVBChannel::frontendStateChanged(iDVBFrontend*fe)
954 {
955         int state, ourstate = 0;
956         
957                 /* if we are already in shutdown, don't change state. */
958         if (m_state == state_release)
959                 return;
960         
961         if (fe->getState(state))
962                 return;
963         
964         if (state == iDVBFrontend::stateLock)
965         {
966                 eDebug("OURSTATE: ok");
967                 ourstate = state_ok;
968         } else if (state == iDVBFrontend::stateTuning)
969         {
970                 eDebug("OURSTATE: tuning");
971                 ourstate = state_tuning;
972         } else if (state == iDVBFrontend::stateLostLock)
973         {
974                         /* on managed channels, we try to retune in order to re-acquire lock. */
975                 if (m_current_frontend_parameters)
976                 {
977                         eDebug("OURSTATE: lost lock, trying to retune");
978                         ourstate = state_tuning;
979                         m_frontend->get().tune(*m_current_frontend_parameters);
980                 } else
981                         /* on unmanaged channels, we don't do this. the client will do this. */
982                 {
983                         eDebug("OURSTATE: lost lock, unavailable now.");
984                         ourstate = state_unavailable;
985                 }
986         } else if (state == iDVBFrontend::stateFailed)
987         {
988                 eDebug("OURSTATE: failed");
989                 ourstate = state_failed;
990         } else
991                 eFatal("state unknown");
992         
993         if (ourstate != m_state)
994         {
995                 m_state = ourstate;
996                 m_stateChanged(this);
997         }
998 }
999
1000 void eDVBChannel::pvrEvent(int event)
1001 {
1002         switch (event)
1003         {
1004         case eFilePushThread::evtEOF:
1005                 eDebug("eDVBChannel: End of file!");
1006                 m_event(this, evtEOF);
1007                 break;
1008         case eFilePushThread::evtUser: /* start */
1009                 eDebug("SOF");
1010                 m_event(this, evtSOF);
1011                 break;
1012         }
1013 }
1014
1015 void eDVBChannel::cueSheetEvent(int event)
1016 {
1017         switch (event)
1018         {
1019         case eCueSheet::evtSeek:
1020                 eDebug("seek.");
1021                 flushPVR(m_cue->m_decoding_demux);
1022                 break;
1023         case eCueSheet::evtSkipmode:
1024         {
1025                 {
1026                         m_cue->m_lock.WrLock();
1027                         m_cue->m_seek_requests.push_back(std::pair<int, pts_t>(1, 0)); /* resync */
1028                         m_cue->m_lock.Unlock();
1029                         eRdLocker l(m_cue->m_lock);
1030                         if (m_cue->m_skipmode_ratio)
1031                         {
1032                                 int bitrate = m_tstools.calcBitrate(); /* in bits/s */
1033                                 eDebug("skipmode ratio is %lld:90000, bitrate is %d bit/s", m_cue->m_skipmode_ratio, bitrate);
1034                                                 /* i agree that this might look a bit like black magic. */
1035                                 m_skipmode_n = 512*1024; /* must be 1 iframe at least. */
1036                                 m_skipmode_m = bitrate / 8 / 90000 * m_cue->m_skipmode_ratio / 8;
1037
1038                                 if (m_cue->m_skipmode_ratio < 0)
1039                                         m_skipmode_m -= m_skipmode_n;
1040
1041                                 eDebug("resolved to: %d %d", m_skipmode_m, m_skipmode_n);
1042
1043                                 if (abs(m_skipmode_m) < abs(m_skipmode_n))
1044                                 {
1045                                         eWarning("something is wrong with this calculation");
1046                                         m_skipmode_n = m_skipmode_m = 0;
1047                                 }
1048                         } else
1049                         {
1050                                 eDebug("skipmode ratio is 0, normal play");
1051                                 m_skipmode_n = m_skipmode_m = 0;
1052                         }
1053                 }
1054                 ASSERT(m_pvr_thread);
1055                 m_pvr_thread->setIFrameSearch(m_skipmode_n != 0);
1056                 if (m_cue->m_skipmode_ratio != 0)
1057                         m_pvr_thread->setTimebaseChange(0x10000 * 9000 / (m_cue->m_skipmode_ratio / 10)); /* negative values are also ok */
1058                 else
1059                         m_pvr_thread->setTimebaseChange(0); /* normal playback */
1060                 eDebug("flush pvr");
1061                 flushPVR(m_cue->m_decoding_demux);
1062                 eDebug("done");
1063                 break;
1064         }
1065         case eCueSheet::evtSpanChanged:
1066         {
1067                 m_source_span.clear();
1068                 for (std::list<std::pair<pts_t, pts_t> >::const_iterator i(m_cue->m_spans.begin()); i != m_cue->m_spans.end(); ++i)
1069                 {
1070                         off_t offset_in, offset_out;
1071                         pts_t pts_in = i->first, pts_out = i->second;
1072                         if (m_tstools.getOffset(offset_in, pts_in) || m_tstools.getOffset(offset_out, pts_out))
1073                         {
1074                                 eDebug("span translation failed.\n");
1075                                 continue;
1076                         }
1077                         eDebug("source span: %llx .. %llx, translated to %llx..%llx", pts_in, pts_out, offset_in, offset_out);
1078                         m_source_span.push_back(std::pair<off_t, off_t>(offset_in, offset_out));
1079                 }
1080                 break;
1081         }
1082         }
1083 }
1084
1085         /* align toward zero */
1086 static inline long long align(long long x, int align)
1087 {
1088         int sign = x < 0;
1089
1090         if (sign)
1091                 x = -x;
1092
1093         x -= x % align;
1094
1095         if (sign)
1096                 x = -x;
1097
1098         return x;
1099 }
1100
1101         /* remember, this gets called from another thread. */
1102 void eDVBChannel::getNextSourceSpan(off_t current_offset, size_t bytes_read, off_t &start, size_t &size)
1103 {
1104         const int blocksize = 188;
1105         unsigned int max = align(10*1024*1024, blocksize);
1106         current_offset = align(current_offset, blocksize);
1107         
1108         if (!m_cue)
1109         {
1110                 eDebug("no cue sheet. forcing normal play");
1111                 start = current_offset;
1112                 size = max;
1113                 return;
1114         }
1115
1116         m_cue->m_lock.RdLock();
1117         if (!m_cue->m_decoding_demux)
1118         {
1119                 start = current_offset;
1120                 size = max;
1121                 eDebug("getNextSourceSpan, no decoding demux. forcing normal play");
1122                 m_cue->m_lock.Unlock();
1123                 return;
1124         }
1125
1126         if (m_skipmode_n)
1127         {
1128                 eDebug("skipmode %d:%d", m_skipmode_m, m_skipmode_n);
1129                 max = align(m_skipmode_n, blocksize);
1130         }
1131
1132         eDebug("getNextSourceSpan, current offset is %08llx, m_skipmode_m = %d!", current_offset, m_skipmode_m);
1133
1134         current_offset += align(m_skipmode_m, blocksize);
1135
1136         while (!m_cue->m_seek_requests.empty())
1137         {
1138                 std::pair<int, pts_t> seek = m_cue->m_seek_requests.front();
1139                 m_cue->m_lock.Unlock();
1140                 m_cue->m_lock.WrLock();
1141                 m_cue->m_seek_requests.pop_front();
1142                 m_cue->m_lock.Unlock();
1143                 m_cue->m_lock.RdLock();
1144                 int relative = seek.first;
1145                 pts_t pts = seek.second;
1146
1147                 pts_t now = 0;
1148                 if (relative)
1149                 {
1150                         if (!m_cue->m_decoder)
1151                         {
1152                                 eDebug("no decoder - can't seek relative");
1153                                 continue;
1154                         }
1155                         if (m_cue->m_decoder->getPTS(0, now))
1156                         {
1157                                 eDebug("decoder getPTS failed, can't seek relative");
1158                                 continue;
1159                         }
1160                         if (getCurrentPosition(m_cue->m_decoding_demux, now, 1))
1161                         {
1162                                 eDebug("seekTo: getCurrentPosition failed!");
1163                                 continue;
1164                         }
1165                 } else if (pts < 0) /* seek relative to end */
1166                 {
1167                         pts_t len;
1168                         if (!getLength(len))
1169                         {
1170                                 eDebug("seeking relative to end. len=%lld, seek = %lld", len, pts);
1171                                 pts += len;
1172                         } else
1173                         {
1174                                 eWarning("getLength failed - can't seek relative to end!");
1175                                 continue;
1176                         }
1177                 }
1178                 
1179                 if (relative == 1) /* pts relative */
1180                 {
1181                         pts += now;
1182                         if (pts < 0)
1183                                 pts = 0;
1184                 }
1185
1186                 if (relative != 2)
1187                         if (pts < 0)
1188                                 pts = 0;
1189                 
1190                 if (relative == 2) /* AP relative */
1191                 {
1192                         eDebug("AP relative seeking: %lld, at %lld", pts, now);
1193                         pts_t nextap;
1194                         if (m_tstools.getNextAccessPoint(nextap, now, pts))
1195                         {
1196                                 pts = now - 90000; /* approx. 1s */
1197                                 eDebug("AP relative seeking failed!");
1198                         } else
1199                         {
1200                                 eDebug("next ap is %llx\n", pts);
1201                                 pts = nextap;
1202                         }
1203                 }
1204                 
1205                 off_t offset = 0;
1206                 if (m_tstools.getOffset(offset, pts))
1207                 {
1208                         eDebug("get offset for pts=%lld failed!", pts);
1209                         continue;
1210                 }
1211
1212                 eDebug("ok, resolved skip (rel: %d, diff %lld), now at %08llx", relative, pts, offset);
1213                 current_offset = align(offset, blocksize); /* in case tstools return non-aligned offset */
1214         }
1215
1216         m_cue->m_lock.Unlock();
1217
1218         for (std::list<std::pair<off_t, off_t> >::const_iterator i(m_source_span.begin()); i != m_source_span.end(); ++i)
1219         {
1220                 long long aligned_start = align(i->first, blocksize);
1221                 long long aligned_end = align(i->second, blocksize);
1222         
1223                 if ((current_offset >= aligned_start) && (current_offset < aligned_end))
1224                 {
1225                         start = current_offset;
1226                                 /* max can not exceed max(size_t). aligned_end - current_offset, however, can. */
1227                         if ((aligned_end - current_offset) > max)
1228                                 size = max;
1229                         else
1230                                 size = aligned_end - current_offset;
1231                         eDebug("HIT, %lld < %lld < %lld, size: %d", i->first, current_offset, i->second, size);
1232                         return;
1233                 }
1234                 if (current_offset < aligned_start)
1235                 {
1236                                 /* ok, our current offset is in an 'out' zone. */
1237                         if ((m_skipmode_m >= 0) || (i == m_source_span.begin()))
1238                         {
1239                                         /* in normal playback, just start at the next zone. */
1240                                 start = i->first;
1241
1242                                         /* size is not 64bit! */
1243                                 if ((i->second - i->first) > max)
1244                                         size = max;
1245                                 else
1246                                         size = aligned_end - aligned_start;
1247
1248                                 eDebug("skip");
1249                                 if (m_skipmode_m < 0)
1250                                 {
1251                                         eDebug("reached SOF");
1252                                                 /* reached SOF */
1253                                         m_skipmode_m = 0;
1254                                         m_pvr_thread->sendEvent(eFilePushThread::evtUser);
1255                                 }
1256                         } else
1257                         {
1258                                         /* when skipping reverse, however, choose the zone before. */
1259                                 --i;
1260                                 eDebug("skip to previous block, which is %llx..%llx", i->first, i->second);
1261                                 size_t len;
1262
1263                                 aligned_start = align(i->first, blocksize);
1264                                 aligned_end = align(i->second, blocksize);
1265
1266                                 if ((aligned_end - aligned_start) > max)
1267                                         len = max;
1268                                 else
1269                                         len = aligned_end - aligned_start;
1270
1271                                 start = aligned_end - len;
1272                                 eDebug("skipping to %llx, %d", start, len);
1273                         }
1274
1275                         eDebug("result: %llx, %x (%llx %llx)", start, size, aligned_start, aligned_end);
1276                         return;
1277                 }
1278         }
1279
1280         if ((current_offset < -m_skipmode_m) && (m_skipmode_m < 0))
1281         {
1282                 eDebug("reached SOF");
1283                 m_skipmode_m = 0;
1284                 m_pvr_thread->sendEvent(eFilePushThread::evtUser);
1285         }
1286
1287         start = current_offset;
1288         size = max;
1289
1290         eDebug("END OF CUESHEET. (%08llx, %d)", start, size);
1291         return;
1292 }
1293
1294 void eDVBChannel::AddUse()
1295 {
1296         if (++m_use_count > 1 && m_state == state_last_instance)
1297         {
1298                 m_state = state_ok;
1299                 m_stateChanged(this);
1300         }
1301 }
1302
1303 void eDVBChannel::ReleaseUse()
1304 {
1305         if (!--m_use_count)
1306         {
1307                 m_state = state_release;
1308                 m_stateChanged(this);
1309         }
1310         else if (m_use_count == 1)
1311         {
1312                 m_state = state_last_instance;
1313                 m_stateChanged(this);
1314         }
1315 }
1316
1317 RESULT eDVBChannel::setChannel(const eDVBChannelID &channelid, ePtr<iDVBFrontendParameters> &feparm)
1318 {
1319         if (m_channel_id)
1320                 m_mgr->removeChannel(this);
1321                 
1322         if (!channelid)
1323                 return 0;
1324
1325         if (!m_frontend)
1326         {
1327                 eDebug("no frontend to tune!");
1328                 return -ENODEV;
1329         }
1330         
1331         m_channel_id = channelid;
1332         m_mgr->addChannel(channelid, this);
1333         m_state = state_tuning;
1334                         /* if tuning fails, shutdown the channel immediately. */
1335         int res;
1336         res = m_frontend->get().tune(*feparm);
1337         m_current_frontend_parameters = feparm;
1338         
1339         if (res)
1340         {
1341                 m_state = state_release;
1342                 m_stateChanged(this);
1343                 return res;
1344         }
1345         
1346         return 0;
1347 }
1348
1349 RESULT eDVBChannel::connectStateChange(const Slot1<void,iDVBChannel*> &stateChange, ePtr<eConnection> &connection)
1350 {
1351         connection = new eConnection((iDVBChannel*)this, m_stateChanged.connect(stateChange));
1352         return 0;
1353 }
1354
1355 RESULT eDVBChannel::connectEvent(const Slot2<void,iDVBChannel*,int> &event, ePtr<eConnection> &connection)
1356 {
1357         connection = new eConnection((iDVBChannel*)this, m_event.connect(event));
1358         return 0;
1359 }
1360
1361 RESULT eDVBChannel::getState(int &state)
1362 {
1363         state = m_state;
1364         return 0;
1365 }
1366
1367 RESULT eDVBChannel::setCIRouting(const eDVBCIRouting &routing)
1368 {
1369         return -1;
1370 }
1371
1372 RESULT eDVBChannel::getDemux(ePtr<iDVBDemux> &demux, int cap)
1373 {
1374         ePtr<eDVBAllocatedDemux> &our_demux = (cap & capDecode) ? m_decoder_demux : m_demux;
1375         
1376         if (!our_demux)
1377         {
1378                 demux = 0;
1379                 
1380                 if (m_mgr->allocateDemux(m_frontend ? (eDVBRegisteredFrontend*)*m_frontend : (eDVBRegisteredFrontend*)0, our_demux, cap))
1381                         return -1;
1382         }
1383         
1384         demux = *our_demux;
1385                 /* don't hold a reference to the decoding demux, we don't need it. */
1386                 
1387                 /* FIXME: by dropping the 'allocated demux' in favour of the 'iDVBDemux',
1388                    the refcount is lost. thus, decoding demuxes are never allocated. 
1389                    
1390                    this poses a big problem for PiP. */
1391         if (cap & capDecode)
1392                 our_demux = 0;
1393         return 0;
1394 }
1395
1396 RESULT eDVBChannel::getFrontend(ePtr<iDVBFrontend> &frontend)
1397 {
1398         frontend = 0;
1399         if (!m_frontend)
1400                 return -ENODEV;
1401         frontend = &m_frontend->get();
1402         if (frontend)
1403                 return 0;
1404         return -ENODEV;
1405 }
1406
1407 RESULT eDVBChannel::getCurrentFrontendParameters(ePtr<iDVBFrontendParameters> &param)
1408 {
1409         param = m_current_frontend_parameters;
1410         return 0;
1411 }
1412
1413 RESULT eDVBChannel::playFile(const char *file)
1414 {
1415         ASSERT(!m_frontend);
1416         if (m_pvr_thread)
1417         {
1418                 m_pvr_thread->stop();
1419                 delete m_pvr_thread;
1420                 m_pvr_thread = 0;
1421         }
1422         
1423         m_tstools.openFile(file);
1424         
1425                 /* DON'T EVEN THINK ABOUT FIXING THIS. FIX THE ATI SOURCES FIRST,
1426                    THEN DO A REAL FIX HERE! */
1427         
1428                 /* (this codepath needs to be improved anyway.) */
1429 #if HAVE_DVB_API_VERSION < 3
1430         m_pvr_fd_dst = open("/dev/pvr", O_WRONLY);
1431 #else
1432         m_pvr_fd_dst = open("/dev/misc/pvr", O_WRONLY);
1433 #endif
1434         if (m_pvr_fd_dst < 0)
1435         {
1436                 eDebug("can't open /dev/misc/pvr - you need to buy the new(!) $$$ box! (%m)"); // or wait for the driver to be improved.
1437                 return -ENODEV;
1438         }
1439
1440         m_pvr_thread = new eDVBChannelFilePush();
1441         m_pvr_thread->enablePVRCommit(1);
1442         m_pvr_thread->setStreamMode(1);
1443         m_pvr_thread->setScatterGather(this);
1444
1445         if (m_pvr_thread->start(file, m_pvr_fd_dst))
1446         {
1447                 delete m_pvr_thread;
1448                 m_pvr_thread = 0;
1449                 eDebug("can't open PVR file %s (%m)", file);
1450                 return -ENOENT;
1451         }
1452         CONNECT(m_pvr_thread->m_event, eDVBChannel::pvrEvent);
1453
1454         m_state = state_ok;
1455         m_stateChanged(this);
1456
1457         return 0;
1458 }
1459
1460 void eDVBChannel::stopFile()
1461 {
1462         if (m_pvr_thread)
1463         {
1464                 m_pvr_thread->stop();
1465                 ::close(m_pvr_fd_dst);
1466                 delete m_pvr_thread;
1467                 m_pvr_thread = 0;
1468         }
1469 }
1470
1471 void eDVBChannel::setCueSheet(eCueSheet *cuesheet)
1472 {
1473         m_conn_cueSheetEvent = 0;
1474         m_cue = cuesheet;
1475         if (m_cue)
1476                 m_cue->connectEvent(slot(*this, &eDVBChannel::cueSheetEvent), m_conn_cueSheetEvent);
1477 }
1478
1479 RESULT eDVBChannel::getLength(pts_t &len)
1480 {
1481         return m_tstools.calcLen(len);
1482 }
1483
1484 RESULT eDVBChannel::getCurrentPosition(iDVBDemux *decoding_demux, pts_t &pos, int mode)
1485 {
1486         if (!decoding_demux)
1487                 return -1;
1488         
1489         pts_t now;
1490         
1491         int r;
1492         
1493         if (mode == 0) /* demux */
1494         {
1495                 r = decoding_demux->getSTC(now, 0);
1496                 if (r)
1497                 {
1498                         eDebug("demux getSTC failed");
1499                         return -1;
1500                 }
1501         } else
1502                 now = pos; /* fixup supplied */
1503         
1504         off_t off = 0; /* TODO: fixme */
1505         r = m_tstools.fixupPTS(off, now);
1506         if (r)
1507         {
1508                 eDebug("fixup PTS failed");
1509                 return -1;
1510         }
1511         
1512         pos = now;
1513         
1514         return 0;
1515 }
1516
1517 void eDVBChannel::flushPVR(iDVBDemux *decoding_demux)
1518 {
1519                         /* when seeking, we have to ensure that all buffers are flushed.
1520                            there are basically 3 buffers:
1521                            a.) the filepush's internal buffer
1522                            b.) the PVR buffer (before demux)
1523                            c.) the ratebuffer (after demux)
1524                            
1525                            it's important to clear them in the correct order, otherwise
1526                            the ratebuffer (for example) would immediately refill from
1527                            the not-yet-flushed PVR buffer.
1528                         */
1529
1530         m_pvr_thread->pause();
1531                 /* flush internal filepush buffer */
1532         m_pvr_thread->flush();
1533                 /* HACK: flush PVR buffer */
1534         ::ioctl(m_pvr_fd_dst, 0);
1535         
1536                 /* flush ratebuffers (video, audio) */
1537         if (decoding_demux)
1538                 decoding_demux->flush();
1539
1540                 /* demux will also flush all decoder.. */
1541                 /* resume will re-query the SG */
1542         m_pvr_thread->resume();
1543 }
1544
1545 DEFINE_REF(eCueSheet);
1546
1547 eCueSheet::eCueSheet()
1548 {
1549         m_skipmode_ratio = 0;
1550 }
1551
1552 void eCueSheet::seekTo(int relative, const pts_t &pts)
1553 {
1554         m_lock.WrLock();
1555         m_seek_requests.push_back(std::pair<int, pts_t>(relative, pts));
1556         m_lock.Unlock();
1557         m_event(evtSeek);
1558 }
1559         
1560 void eCueSheet::clear()
1561 {
1562         m_lock.WrLock();
1563         m_spans.clear();
1564         m_lock.Unlock();
1565 }
1566
1567 void eCueSheet::addSourceSpan(const pts_t &begin, const pts_t &end)
1568 {
1569         assert(begin < end);
1570         m_lock.WrLock();
1571         m_spans.push_back(std::pair<pts_t, pts_t>(begin, end));
1572         m_lock.Unlock();
1573 }
1574
1575 void eCueSheet::commitSpans()
1576 {
1577         m_event(evtSpanChanged);
1578 }
1579
1580 void eCueSheet::setSkipmode(const pts_t &ratio)
1581 {
1582         m_lock.WrLock();
1583         m_skipmode_ratio = ratio;
1584         m_lock.Unlock();
1585         m_event(evtSkipmode);
1586 }
1587
1588 void eCueSheet::setDecodingDemux(iDVBDemux *demux, iTSMPEGDecoder *decoder)
1589 {
1590         m_decoding_demux = demux;
1591         m_decoder = decoder;
1592 }
1593
1594 RESULT eCueSheet::connectEvent(const Slot1<void,int> &event, ePtr<eConnection> &connection)
1595 {
1596         connection = new eConnection(this, m_event.connect(event));
1597         return 0;
1598 }