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