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 #include <lib/dvb/specs.h>
10 #include <sys/types.h>
14 #include <sys/ioctl.h>
16 DEFINE_REF(eDVBRegisteredFrontend);
17 DEFINE_REF(eDVBRegisteredDemux);
19 DEFINE_REF(eDVBAllocatedFrontend);
21 eDVBAllocatedFrontend::eDVBAllocatedFrontend(eDVBRegisteredFrontend *fe): m_fe(fe)
26 eDVBAllocatedFrontend::~eDVBAllocatedFrontend()
31 DEFINE_REF(eDVBAllocatedDemux);
33 eDVBAllocatedDemux::eDVBAllocatedDemux(eDVBRegisteredDemux *demux): m_demux(demux)
38 eDVBAllocatedDemux::~eDVBAllocatedDemux()
43 DEFINE_REF(eDVBResourceManager);
45 eDVBResourceManager *eDVBResourceManager::instance;
47 RESULT eDVBResourceManager::getInstance(ePtr<eDVBResourceManager> &ptr)
57 ePtr<eDVBResourceManager> NewResourceManagerPtr(void)
59 ePtr<eDVBResourceManager> ptr;
60 eDVBResourceManager::getInstance(ptr);
64 eDVBResourceManager::eDVBResourceManager()
65 :m_releaseCachedChannelTimer(eTimer::create(eApp))
69 m_sec = new eDVBSatelliteEquipmentControl(m_frontend, m_simulate_frontend);
74 /* search available adapters... */
79 while (eDVBAdapterLinux::exist(num_adapter))
81 addAdapter(new eDVBAdapterLinux(num_adapter));
85 int fd = open("/proc/stb/info/model", O_RDONLY);
87 int rd = fd >= 0 ? read(fd, tmp, 255) : 0;
91 if (!strncmp(tmp, "dm7025\n", rd))
93 else if (!strncmp(tmp, "dm8000\n", rd))
95 else if (!strncmp(tmp, "dm800\n", rd))
97 else if (!strncmp(tmp, "dm500hd\n", rd))
100 eDebug("boxtype detection via /proc/stb/info not possible... use fallback via demux count!\n");
101 if (m_demux.size() == 3)
103 else if (m_demux.size() < 5)
109 eDebug("found %d adapter, %d frontends(%d sim) and %d demux, boxtype %d",
110 m_adapter.size(), m_frontend.size(), m_simulate_frontend.size(), m_demux.size(), m_boxtype);
112 eDVBCAService::registerChannelCallback(this);
114 CONNECT(m_releaseCachedChannelTimer->timeout, eDVBResourceManager::releaseCachedChannel);
117 void eDVBResourceManager::feStateChanged()
120 for (eSmartPtrList<eDVBRegisteredFrontend>::iterator i(m_frontend.begin()); i != m_frontend.end(); ++i)
122 mask |= ( 1 << i->m_frontend->getSlotID() );
123 /* emit */ frontendUseMaskChanged(mask);
126 DEFINE_REF(eDVBAdapterLinux);
127 eDVBAdapterLinux::eDVBAdapterLinux(int nr): m_nr(nr)
132 eDebug("scanning for frontends..");
137 #if HAVE_DVB_API_VERSION < 3
138 sprintf(filename, "/dev/dvb/card%d/frontend%d", m_nr, num_fe);
140 sprintf(filename, "/dev/dvb/adapter%d/frontend%d", m_nr, num_fe);
142 if (stat(filename, &s))
144 ePtr<eDVBFrontend> fe;
148 fe = new eDVBFrontend(m_nr, num_fe, ok);
150 m_frontend.push_back(fe);
154 fe = new eDVBFrontend(m_nr, num_fe, ok, true);
156 m_simulate_frontend.push_back(fe);
167 #if HAVE_DVB_API_VERSION < 3
168 sprintf(filename, "/dev/dvb/card%d/demux%d", m_nr, num_demux);
170 sprintf(filename, "/dev/dvb/adapter%d/demux%d", m_nr, num_demux);
172 if (stat(filename, &s))
174 ePtr<eDVBDemux> demux;
176 demux = new eDVBDemux(m_nr, num_demux);
177 m_demux.push_back(demux);
183 int eDVBAdapterLinux::getNumDemux()
185 return m_demux.size();
188 RESULT eDVBAdapterLinux::getDemux(ePtr<eDVBDemux> &demux, int nr)
190 eSmartPtrList<eDVBDemux>::iterator i(m_demux.begin());
191 while (nr && (i != m_demux.end()))
197 if (i != m_demux.end())
205 int eDVBAdapterLinux::getNumFrontends()
207 return m_frontend.size();
210 RESULT eDVBAdapterLinux::getFrontend(ePtr<eDVBFrontend> &fe, int nr, bool simulate)
212 eSmartPtrList<eDVBFrontend>::iterator i(simulate ? m_simulate_frontend.begin() : m_frontend.begin());
213 while (nr && (i != m_frontend.end()))
219 if (i != m_frontend.end())
227 int eDVBAdapterLinux::exist(int nr)
231 #if HAVE_DVB_API_VERSION < 3
232 sprintf(filename, "/dev/dvb/card%d", nr);
234 sprintf(filename, "/dev/dvb/adapter%d", nr);
236 if (!stat(filename, &s))
241 eDVBResourceManager::~eDVBResourceManager()
243 if (instance == this)
247 void eDVBResourceManager::addAdapter(iDVBAdapter *adapter)
249 int num_fe = adapter->getNumFrontends();
250 int num_demux = adapter->getNumDemux();
252 m_adapter.push_back(adapter);
255 for (i=0; i<num_demux; ++i)
257 ePtr<eDVBDemux> demux;
258 if (!adapter->getDemux(demux, i))
259 m_demux.push_back(new eDVBRegisteredDemux(demux, adapter));
262 ePtr<eDVBRegisteredFrontend> prev_dvbt_frontend;
263 for (i=0; i<num_fe; ++i)
265 ePtr<eDVBFrontend> frontend;
266 if (!adapter->getFrontend(frontend, i))
269 frontend->getFrontendType(frontendType);
270 eDVBRegisteredFrontend *new_fe = new eDVBRegisteredFrontend(frontend, adapter);
271 CONNECT(new_fe->stateChanged, eDVBResourceManager::feStateChanged);
272 m_frontend.push_back(new_fe);
273 frontend->setSEC(m_sec);
274 // we must link all dvb-t frontends ( for active antenna voltage )
275 if (frontendType == iDVBFrontend::feTerrestrial)
277 if (prev_dvbt_frontend)
279 prev_dvbt_frontend->m_frontend->setData(eDVBFrontend::LINKED_NEXT_PTR, (long)new_fe);
280 frontend->setData(eDVBFrontend::LINKED_PREV_PTR, (long)&(*prev_dvbt_frontend));
282 prev_dvbt_frontend = new_fe;
287 prev_dvbt_frontend = 0;
288 for (i=0; i<num_fe; ++i)
290 ePtr<eDVBFrontend> frontend;
291 if (!adapter->getFrontend(frontend, i, true))
294 frontend->getFrontendType(frontendType);
295 eDVBRegisteredFrontend *new_fe = new eDVBRegisteredFrontend(frontend, adapter);
296 // CONNECT(new_fe->stateChanged, eDVBResourceManager::feStateChanged);
297 m_simulate_frontend.push_back(new_fe);
298 frontend->setSEC(m_sec);
299 // we must link all dvb-t frontends ( for active antenna voltage )
300 if (frontendType == iDVBFrontend::feTerrestrial)
302 if (prev_dvbt_frontend)
304 prev_dvbt_frontend->m_frontend->setData(eDVBFrontend::LINKED_NEXT_PTR, (long)new_fe);
305 frontend->setData(eDVBFrontend::LINKED_PREV_PTR, (long)&(*prev_dvbt_frontend));
307 prev_dvbt_frontend = new_fe;
314 PyObject *eDVBResourceManager::setFrontendSlotInformations(ePyObject list)
316 if (!PyList_Check(list))
318 PyErr_SetString(PyExc_StandardError, "eDVBResourceManager::setFrontendSlotInformations argument should be a python list");
321 if ((unsigned int)PyList_Size(list) != m_frontend.size())
324 sprintf(blasel, "eDVBResourceManager::setFrontendSlotInformations list size incorrect %d frontends avail, but %d entries in slotlist",
325 m_frontend.size(), PyList_Size(list));
326 PyErr_SetString(PyExc_StandardError, blasel);
330 for (eSmartPtrList<eDVBRegisteredFrontend>::iterator i(m_frontend.begin()); i != m_frontend.end(); ++i)
332 ePyObject obj = PyList_GET_ITEM(list, pos++);
333 if (!i->m_frontend->setSlotInfo(obj))
337 for (eSmartPtrList<eDVBRegisteredFrontend>::iterator i(m_simulate_frontend.begin()); i != m_simulate_frontend.end(); ++i)
339 ePyObject obj = PyList_GET_ITEM(list, pos++);
340 if (!i->m_frontend->setSlotInfo(obj))
346 RESULT eDVBResourceManager::allocateFrontend(ePtr<eDVBAllocatedFrontend> &fe, ePtr<iDVBFrontendParameters> &feparm, bool simulate)
348 eSmartPtrList<eDVBRegisteredFrontend> &frontends = simulate ? m_simulate_frontend : m_frontend;
349 ePtr<eDVBRegisteredFrontend> best;
353 for (eSmartPtrList<eDVBRegisteredFrontend>::iterator i(frontends.begin()); i != frontends.end(); ++i)
355 int c = i->m_frontend->isCompatibleWith(feparm);
357 if (c) /* if we have at least one frontend which is compatible with the source, flag this. */
362 // eDebug("Slot %d, score %d", i->m_frontend->getSlotID(), c);
370 // eDebug("Slot %d, score %d... but BUSY!!!!!!!!!!!", i->m_frontend->getSlotID(), c);
375 fe = new eDVBAllocatedFrontend(best);
382 return errAllSourcesBusy;
384 return errNoSourceFound;
387 RESULT eDVBResourceManager::allocateFrontendByIndex(ePtr<eDVBAllocatedFrontend> &fe, int slot_index)
389 int err = errNoSourceFound;
390 for (eSmartPtrList<eDVBRegisteredFrontend>::iterator i(m_frontend.begin()); i != m_frontend.end(); ++i)
391 if (!i->m_inuse && i->m_frontend->getSlotID() == slot_index)
393 // check if another slot linked to this is in use
395 i->m_frontend->getData(eDVBFrontend::SATPOS_DEPENDS_PTR, tmp);
398 eDVBRegisteredFrontend *satpos_depends_to_fe = (eDVBRegisteredFrontend *)tmp;
399 if (satpos_depends_to_fe->m_inuse)
401 eDebug("another satpos depending frontend is in use.. so allocateFrontendByIndex not possible!");
402 err = errAllSourcesBusy;
403 goto alloc_fe_by_id_not_possible;
406 else // check linked tuners
408 i->m_frontend->getData(eDVBFrontend::LINKED_NEXT_PTR, tmp);
411 eDVBRegisteredFrontend *next = (eDVBRegisteredFrontend *) tmp;
414 eDebug("another linked frontend is in use.. so allocateFrontendByIndex not possible!");
415 err = errAllSourcesBusy;
416 goto alloc_fe_by_id_not_possible;
418 next->m_frontend->getData(eDVBFrontend::LINKED_NEXT_PTR, tmp);
420 i->m_frontend->getData(eDVBFrontend::LINKED_PREV_PTR, tmp);
423 eDVBRegisteredFrontend *prev = (eDVBRegisteredFrontend *) tmp;
426 eDebug("another linked frontend is in use.. so allocateFrontendByIndex not possible!");
427 err = errAllSourcesBusy;
428 goto alloc_fe_by_id_not_possible;
430 prev->m_frontend->getData(eDVBFrontend::LINKED_PREV_PTR, tmp);
433 fe = new eDVBAllocatedFrontend(i);
436 alloc_fe_by_id_not_possible:
441 #define capHoldDecodeReference 64
443 RESULT eDVBResourceManager::allocateDemux(eDVBRegisteredFrontend *fe, ePtr<eDVBAllocatedDemux> &demux, int &cap)
445 /* find first unused demux which is on same adapter as frontend (or any, if PVR)
446 never use the first one unless we need a decoding demux. */
448 eDebug("allocate demux");
449 eSmartPtrList<eDVBRegisteredDemux>::iterator i(m_demux.begin());
453 if (i == m_demux.end())
456 ePtr<eDVBRegisteredDemux> unused;
458 if (m_boxtype == DM800 || m_boxtype == DM500HD) // dm800 / 500hd
460 cap |= capHoldDecodeReference; // this is checked in eDVBChannel::getDemux
461 for (; i != m_demux.end(); ++i, ++n)
472 if (i->m_adapter == fe->m_adapter &&
473 i->m_demux->getSource() == fe->m_frontend->getDVBID())
475 demux = new eDVBAllocatedDemux(i);
479 else if (i->m_demux->getSource() == -1) // PVR
481 demux = new eDVBAllocatedDemux(i);
487 else if (m_boxtype == DM7025) // ATI
489 /* FIXME: hardware demux policy */
490 if (!(cap & iDVBChannel::capDecode))
492 if (m_demux.size() > 2) /* assumed to be true, otherwise we have lost anyway */
499 for (; i != m_demux.end(); ++i, ++n)
501 int is_decode = n < 2;
503 int in_use = is_decode ? (i->m_demux->getRefCount() != 2) : i->m_inuse;
505 if ((!in_use) && ((!fe) || (i->m_adapter == fe->m_adapter)))
507 if ((cap & iDVBChannel::capDecode) && !is_decode)
514 else if (m_boxtype == DM8000)
516 cap |= capHoldDecodeReference; // this is checked in eDVBChannel::getDemux
517 for (; i != m_demux.end(); ++i, ++n)
526 else if (i->m_adapter == fe->m_adapter &&
527 i->m_demux->getSource() == fe->m_frontend->getDVBID())
529 demux = new eDVBAllocatedDemux(i);
533 else if (n == 4) // always use demux4 for PVR (demux 4 can not descramble...)
536 demux = new eDVBAllocatedDemux(i);
546 demux = new eDVBAllocatedDemux(unused);
548 demux->get().setSourceFrontend(fe->m_frontend->getDVBID());
550 demux->get().setSourcePVR(0);
554 eDebug("demux not found");
558 RESULT eDVBResourceManager::setChannelList(iDVBChannelList *list)
564 RESULT eDVBResourceManager::getChannelList(ePtr<iDVBChannelList> &list)
573 #define eDebugNoSimulate(x...) \
580 // eDebugNoNewLine("SIMULATE:"); \
585 RESULT eDVBResourceManager::allocateChannel(const eDVBChannelID &channelid, eUsePtr<iDVBChannel> &channel, bool simulate)
587 /* first, check if a channel is already existing. */
588 std::list<active_channel> &active_channels = simulate ? m_active_simulate_channels : m_active_channels;
590 if (!simulate && m_cached_channel)
592 eDVBChannel *cache_chan = (eDVBChannel*)&(*m_cached_channel);
593 if(channelid==cache_chan->getChannelID())
595 eDebug("use cached_channel");
596 channel = m_cached_channel;
599 m_cached_channel_state_changed_conn.disconnect();
601 m_releaseCachedChannelTimer->stop();
604 eDebugNoSimulate("allocate channel.. %04x:%04x", channelid.transport_stream_id.get(), channelid.original_network_id.get());
605 for (std::list<active_channel>::iterator i(active_channels.begin()); i != active_channels.end(); ++i)
607 eDebugNoSimulate("available channel.. %04x:%04x", i->m_channel_id.transport_stream_id.get(), i->m_channel_id.original_network_id.get());
608 if (i->m_channel_id == channelid)
610 eDebugNoSimulate("found shared channel..");
611 channel = i->m_channel;
616 /* no currently available channel is tuned to this channelid. create a new one, if possible. */
620 eDebugNoSimulate("no channel list set!");
621 return errNoChannelList;
624 ePtr<iDVBFrontendParameters> feparm;
625 if (m_list->getChannelFrontendData(channelid, feparm))
627 eDebugNoSimulate("channel not found!");
628 return errChannelNotInList;
631 /* allocate a frontend. */
633 ePtr<eDVBAllocatedFrontend> fe;
635 int err = allocateFrontend(fe, feparm, simulate);
640 ePtr<eDVBChannel> ch = new eDVBChannel(this, fe);
642 res = ch->setChannel(channelid, feparm);
646 return errChidNotFound;
653 m_cached_channel = channel = ch;
654 m_cached_channel_state_changed_conn =
655 CONNECT(ch->m_stateChanged,eDVBResourceManager::DVBChannelStateChanged);
661 void eDVBResourceManager::DVBChannelStateChanged(iDVBChannel *chan)
664 chan->getState(state);
667 case iDVBChannel::state_release:
668 case iDVBChannel::state_ok:
670 eDebug("stop release channel timer");
671 m_releaseCachedChannelTimer->stop();
674 case iDVBChannel::state_last_instance:
676 eDebug("start release channel timer");
677 m_releaseCachedChannelTimer->start(3000, true);
680 default: // ignore all other events
685 void eDVBResourceManager::releaseCachedChannel()
687 eDebug("release cached channel (timer timeout)");
691 RESULT eDVBResourceManager::allocateRawChannel(eUsePtr<iDVBChannel> &channel, int slot_index)
693 ePtr<eDVBAllocatedFrontend> fe;
695 if (m_cached_channel)
697 m_cached_channel_state_changed_conn.disconnect();
699 m_releaseCachedChannelTimer->stop();
702 int err = allocateFrontendByIndex(fe, slot_index);
706 channel = new eDVBChannel(this, fe);
711 RESULT eDVBResourceManager::allocatePVRChannel(eUsePtr<iDVBPVRChannel> &channel)
713 ePtr<eDVBAllocatedDemux> demux;
715 if (m_cached_channel && m_releaseCachedChannelTimer->isActive())
717 m_cached_channel_state_changed_conn.disconnect();
719 m_releaseCachedChannelTimer->stop();
722 channel = new eDVBChannel(this, 0);
726 RESULT eDVBResourceManager::addChannel(const eDVBChannelID &chid, eDVBChannel *ch)
728 ePtr<iDVBFrontend> fe;
729 if (!ch->getFrontend(fe))
731 eDVBFrontend *frontend = (eDVBFrontend*)&(*fe);
732 if (frontend->is_simulate())
733 m_active_simulate_channels.push_back(active_channel(chid, ch));
736 m_active_channels.push_back(active_channel(chid, ch));
737 /* emit */ m_channelAdded(ch);
743 RESULT eDVBResourceManager::removeChannel(eDVBChannel *ch)
745 ePtr<iDVBFrontend> fe;
746 if (!ch->getFrontend(fe))
748 eDVBFrontend *frontend = (eDVBFrontend*)&(*fe);
749 std::list<active_channel> &active_channels = frontend->is_simulate() ? m_active_simulate_channels : m_active_channels;
751 for (std::list<active_channel>::iterator i(active_channels.begin()); i != active_channels.end();)
753 if (i->m_channel == ch)
755 i = active_channels.erase(i);
767 RESULT eDVBResourceManager::connectChannelAdded(const Slot1<void,eDVBChannel*> &channelAdded, ePtr<eConnection> &connection)
769 connection = new eConnection((eDVBResourceManager*)this, m_channelAdded.connect(channelAdded));
773 int eDVBResourceManager::canAllocateFrontend(ePtr<iDVBFrontendParameters> &feparm, bool simulate)
775 eSmartPtrList<eDVBRegisteredFrontend> &frontends = simulate ? m_simulate_frontend : m_frontend;
776 ePtr<eDVBRegisteredFrontend> best;
779 for (eSmartPtrList<eDVBRegisteredFrontend>::iterator i(frontends.begin()); i != frontends.end(); ++i)
782 int c = i->m_frontend->isCompatibleWith(feparm);
789 int tuner_type_channel_default(ePtr<iDVBChannelList> &channellist, const eDVBChannelID &chid)
793 ePtr<iDVBFrontendParameters> feparm;
794 if (!channellist->getChannelFrontendData(chid, feparm))
797 if (!feparm->getSystem(system))
801 case iDVBFrontend::feSatellite:
803 case iDVBFrontend::feCable:
805 case iDVBFrontend::feTerrestrial:
816 int eDVBResourceManager::canAllocateChannel(const eDVBChannelID &channelid, const eDVBChannelID& ignore, bool simulate)
818 std::list<active_channel> &active_channels = simulate ? m_active_simulate_channels : m_active_channels;
820 if (!simulate && m_cached_channel)
822 eDVBChannel *cache_chan = (eDVBChannel*)&(*m_cached_channel);
823 if(channelid==cache_chan->getChannelID())
824 return tuner_type_channel_default(m_list, channelid);
827 /* first, check if a channel is already existing. */
828 // eDebug("allocate channel.. %04x:%04x", channelid.transport_stream_id.get(), channelid.original_network_id.get());
829 for (std::list<active_channel>::iterator i(active_channels.begin()); i != active_channels.end(); ++i)
831 // eDebug("available channel.. %04x:%04x", i->m_channel_id.transport_stream_id.get(), i->m_channel_id.original_network_id.get());
832 if (i->m_channel_id == channelid)
834 // eDebug("found shared channel..");
835 return tuner_type_channel_default(m_list, channelid);
839 int *decremented_cached_channel_fe_usecount=NULL,
840 *decremented_fe_usecount=NULL;
842 for (std::list<active_channel>::iterator i(active_channels.begin()); i != active_channels.end(); ++i)
844 eSmartPtrList<eDVBRegisteredFrontend> &frontends = simulate ? m_simulate_frontend : m_frontend;
845 // eDebug("available channel.. %04x:%04x", i->m_channel_id.transport_stream_id.get(), i->m_channel_id.original_network_id.get());
846 if (i->m_channel_id == ignore)
848 eDVBChannel *channel = (eDVBChannel*) &(*i->m_channel);
849 // one eUsePtr<iDVBChannel> is used in eDVBServicePMTHandler
850 // another on eUsePtr<iDVBChannel> is used in the eDVBScan instance used in eDVBServicePMTHandler (for SDT scan)
851 // so we must check here if usecount is 3 (when the channel is equal to the cached channel)
852 // or 2 when the cached channel is not equal to the compared channel
853 if (channel == &(*m_cached_channel) ? channel->getUseCount() == 3 : channel->getUseCount() == 2) // channel only used once..
855 ePtr<iDVBFrontend> fe;
856 if (!i->m_channel->getFrontend(fe))
858 for (eSmartPtrList<eDVBRegisteredFrontend>::iterator ii(frontends.begin()); ii != frontends.end(); ++ii)
860 if ( &(*fe) == &(*ii->m_frontend) )
863 decremented_fe_usecount = &ii->m_inuse;
864 if (channel == &(*m_cached_channel))
865 decremented_cached_channel_fe_usecount = decremented_fe_usecount;
875 if (!decremented_cached_channel_fe_usecount)
877 if (m_cached_channel)
879 eDVBChannel *channel = (eDVBChannel*) &(*m_cached_channel);
880 if (channel->getUseCount() == 1)
882 ePtr<iDVBFrontend> fe;
883 if (!channel->getFrontend(fe))
885 eSmartPtrList<eDVBRegisteredFrontend> &frontends = simulate ? m_simulate_frontend : m_frontend;
886 for (eSmartPtrList<eDVBRegisteredFrontend>::iterator ii(frontends.begin()); ii != frontends.end(); ++ii)
888 if ( &(*fe) == &(*ii->m_frontend) )
891 decremented_cached_channel_fe_usecount = &ii->m_inuse;
900 decremented_cached_channel_fe_usecount=NULL;
902 ePtr<iDVBFrontendParameters> feparm;
906 eDebug("no channel list set!");
910 if (m_list->getChannelFrontendData(channelid, feparm))
912 eDebug("channel not found!");
916 ret = canAllocateFrontend(feparm, simulate);
919 if (decremented_fe_usecount)
920 ++(*decremented_fe_usecount);
921 if (decremented_cached_channel_fe_usecount)
922 ++(*decremented_cached_channel_fe_usecount);
927 bool eDVBResourceManager::canMeasureFrontendInputPower()
929 for (eSmartPtrList<eDVBRegisteredFrontend>::iterator i(m_frontend.begin()); i != m_frontend.end(); ++i)
931 return i->m_frontend->readInputpower() >= 0;
936 class eDVBChannelFilePush: public eFilePushThread
939 eDVBChannelFilePush() { setIFrameSearch(0); setTimebaseChange(0); }
940 void setIFrameSearch(int enabled) { m_iframe_search = enabled; m_iframe_state = 0; }
942 /* "timebase change" is for doing trickmode playback at an exact speed, even when pictures are skipped. */
943 /* you need to set it to 1/16 if you want 16x playback, for example. you need video master sync. */
944 void setTimebaseChange(int ratio) { m_timebase_change = ratio; } /* 16bit fixpoint, 0 for disable */
946 int m_iframe_search, m_iframe_state, m_pid;
947 int m_timebase_change;
948 int filterRecordData(const unsigned char *data, int len, size_t ¤t_span_remaining);
951 int eDVBChannelFilePush::filterRecordData(const unsigned char *_data, int len, size_t ¤t_span_remaining)
954 if (m_timebase_change)
956 eDebug("timebase change: %d", m_timebase_change);
958 for (offset = 0; offset < len; offset += 188)
960 unsigned char *pkt = (unsigned char*)_data + offset;
961 if (pkt[1] & 0x40) /* pusi */
963 if (pkt[3] & 0x20) // adaption field present?
964 pkt += pkt[4] + 4 + 1; /* skip adaption field and header */
966 pkt += 4; /* skip header */
967 if (pkt[0] || pkt[1] || (pkt[2] != 1))
969 eWarning("broken startcode");
975 if (pkt[7] & 0x80) // PTS present?
977 pts = ((unsigned long long)(pkt[ 9]&0xE)) << 29;
978 pts |= ((unsigned long long)(pkt[10]&0xFF)) << 22;
979 pts |= ((unsigned long long)(pkt[11]&0xFE)) << 14;
980 pts |= ((unsigned long long)(pkt[12]&0xFF)) << 7;
981 pts |= ((unsigned long long)(pkt[13]&0xFE)) >> 1;
985 RESULT r = m_tstools.fixupPTS(off, pts);
987 eWarning("fixup PTS while trickmode playback failed.\n");
990 int sec = pts / 90000;
991 int frm = pts % 90000;
999 // eDebug("original, fixed pts: %016llx %d:%02d:%02d:%02d:%05d", pts, d, hr, min, sec, frm);
1001 pts += 0x80000000LL;
1002 pts *= m_timebase_change;
1014 // eDebug("new pts (after timebase change): %016llx %d:%02d:%02d:%02d:%05d", pts, d, hr, min, sec, frm);
1022 pkt[9] |= (pts >> 29) & 0xE;
1023 pkt[10] |= (pts >> 22) & 0xFF;
1024 pkt[11] |= (pts >> 14) & 0xFE;
1025 pkt[12] |= (pts >> 7) & 0xFF;
1026 pkt[13] |= (pts << 1) & 0xFE;
1034 if (!m_iframe_search)
1037 unsigned char *data = (unsigned char*)_data; /* remove that const. we know what we are doing. */
1039 // eDebug("filterRecordData, size=%d (mod 188=%d), first byte is %02x", len, len %188, data[0]);
1041 unsigned char *d = data;
1042 while ((d + 3 < data + len) && (d = (unsigned char*)memmem(d, data + len - d, "\x00\x00\x01", 3)))
1044 int offset = d - data;
1045 int ts_offset = offset - offset % 188; /* offset to the start of TS packet */
1046 unsigned char *ts = data + ts_offset;
1047 int pid = ((ts[1] << 8) | ts[2]) & 0x1FFF;
1049 if ((d[3] == 0 || d[3] == 0x09 && d[-1] == 0 && (ts[1] & 0x40)) && (m_pid == pid)) /* picture start */
1051 int picture_type = (d[3]==0 ? (d[5] >> 3) & 7 : (d[4] >> 5) + 1);
1054 // eDebug("%d-frame at %d, offset in TS packet: %d, pid=%04x", picture_type, offset, offset % 188, pid);
1056 if (m_iframe_state == 1)
1058 /* we are allowing data, and stop allowing data on the next frame.
1059 we now found a frame. so stop here. */
1060 memset(data + offset, 0, 188 - (offset%188)); /* zero out rest of TS packet */
1061 current_span_remaining = 0;
1063 unsigned char *fts = ts + 188;
1064 while (fts < (data + len))
1067 fts[2] |= 0xff; /* drop packet */
1071 return len; // ts_offset + 188; /* deliver this packet, but not more. */
1074 if (picture_type != 1) /* we are only interested in I frames */
1077 unsigned char *fts = data;
1081 fts[2] |= 0xff; /* drop packet */
1088 } else if ((d[3] & 0xF0) == 0xE0) /* video stream */
1090 /* verify that this is actually a PES header, not just some ES data */
1091 if (ts[1] & 0x40) /* PUSI set */
1093 int payload_start = 4;
1094 if (ts[3] & 0x20) /* adaptation field present */
1095 payload_start += ts[4] + 1; /* skip AF */
1096 if (payload_start == (offset%188)) /* the 00 00 01 should be directly at the payload start, otherwise it's not a PES header */
1100 eDebug("now locked to pid %04x (%02x %02x %02x %02x)", pid, ts[0], ts[1], ts[2], ts[3]);
1108 d += 4; /* ignore */
1111 if (m_iframe_state == 1)
1114 return 0; /* we need find an iframe first */
1120 DEFINE_REF(eDVBChannel);
1122 eDVBChannel::eDVBChannel(eDVBResourceManager *mgr, eDVBAllocatedFrontend *frontend): m_state(state_idle), m_mgr(mgr)
1124 m_frontend = frontend;
1128 m_skipmode_n = m_skipmode_m = m_skipmode_frames = 0;
1131 m_frontend->get().connectStateChange(slot(*this, &eDVBChannel::frontendStateChanged), m_conn_frontendStateChanged);
1134 eDVBChannel::~eDVBChannel()
1137 m_mgr->removeChannel(this);
1142 void eDVBChannel::frontendStateChanged(iDVBFrontend*fe)
1144 int state, ourstate = 0;
1146 /* if we are already in shutdown, don't change state. */
1147 if (m_state == state_release)
1150 if (fe->getState(state))
1153 if (state == iDVBFrontend::stateLock)
1155 eDebug("OURSTATE: ok");
1156 ourstate = state_ok;
1157 } else if (state == iDVBFrontend::stateTuning)
1159 eDebug("OURSTATE: tuning");
1160 ourstate = state_tuning;
1161 } else if (state == iDVBFrontend::stateLostLock)
1163 /* on managed channels, we try to retune in order to re-acquire lock. */
1164 if (m_current_frontend_parameters)
1166 eDebug("OURSTATE: lost lock, trying to retune");
1167 ourstate = state_tuning;
1168 m_frontend->get().tune(*m_current_frontend_parameters);
1170 /* on unmanaged channels, we don't do this. the client will do this. */
1172 eDebug("OURSTATE: lost lock, unavailable now.");
1173 ourstate = state_unavailable;
1175 } else if (state == iDVBFrontend::stateFailed)
1177 eDebug("OURSTATE: failed");
1178 ourstate = state_failed;
1180 eFatal("state unknown");
1182 if (ourstate != m_state)
1185 m_stateChanged(this);
1189 void eDVBChannel::pvrEvent(int event)
1193 case eFilePushThread::evtEOF:
1194 eDebug("eDVBChannel: End of file!");
1195 m_event(this, evtEOF);
1197 case eFilePushThread::evtUser: /* start */
1199 m_event(this, evtSOF);
1204 void eDVBChannel::cueSheetEvent(int event)
1206 /* we might end up here if playing failed or stopped, but the client hasn't (yet) noted. */
1211 case eCueSheet::evtSeek:
1213 flushPVR(m_cue->m_decoding_demux);
1215 case eCueSheet::evtSkipmode:
1218 m_cue->m_lock.WrLock();
1219 m_cue->m_seek_requests.push_back(std::pair<int, pts_t>(1, 0)); /* resync */
1220 m_cue->m_lock.Unlock();
1221 eRdLocker l(m_cue->m_lock);
1222 if (m_cue->m_skipmode_ratio)
1224 int bitrate = m_tstools.calcBitrate(); /* in bits/s */
1225 eDebug("skipmode ratio is %lld:90000, bitrate is %d bit/s", m_cue->m_skipmode_ratio, bitrate);
1226 /* i agree that this might look a bit like black magic. */
1227 m_skipmode_n = 512*1024; /* must be 1 iframe at least. */
1228 m_skipmode_m = bitrate / 8 / 90000 * m_cue->m_skipmode_ratio / 8;
1229 m_skipmode_frames = m_cue->m_skipmode_ratio / 90000;
1230 m_skipmode_frames_remainder = 0;
1232 if (m_cue->m_skipmode_ratio < 0)
1233 m_skipmode_m -= m_skipmode_n;
1235 eDebug("resolved to: %d %d", m_skipmode_m, m_skipmode_n);
1237 if (abs(m_skipmode_m) < abs(m_skipmode_n))
1239 eWarning("something is wrong with this calculation");
1240 m_skipmode_frames = m_skipmode_n = m_skipmode_m = 0;
1244 eDebug("skipmode ratio is 0, normal play");
1245 m_skipmode_frames = m_skipmode_n = m_skipmode_m = 0;
1248 m_pvr_thread->setIFrameSearch(m_skipmode_n != 0);
1249 if (m_cue->m_skipmode_ratio != 0)
1250 m_pvr_thread->setTimebaseChange(0x10000 * 9000 / (m_cue->m_skipmode_ratio / 10)); /* negative values are also ok */
1252 m_pvr_thread->setTimebaseChange(0); /* normal playback */
1253 eDebug("flush pvr");
1254 flushPVR(m_cue->m_decoding_demux);
1258 case eCueSheet::evtSpanChanged:
1260 m_source_span.clear();
1261 for (std::list<std::pair<pts_t, pts_t> >::const_iterator i(m_cue->m_spans.begin()); i != m_cue->m_spans.end(); ++i)
1263 off_t offset_in, offset_out;
1264 pts_t pts_in = i->first, pts_out = i->second;
1265 if (m_tstools.getOffset(offset_in, pts_in, -1) || m_tstools.getOffset(offset_out, pts_out, 1))
1267 eDebug("span translation failed.\n");
1270 eDebug("source span: %llx .. %llx, translated to %llx..%llx", pts_in, pts_out, offset_in, offset_out);
1271 m_source_span.push_back(std::pair<off_t, off_t>(offset_in, offset_out));
1278 /* align toward zero */
1279 static inline long long align(long long x, int align)
1294 /* align toward zero */
1295 static inline long long align_with_len(long long x, int align, size_t &len)
1311 /* remember, this gets called from another thread. */
1312 void eDVBChannel::getNextSourceSpan(off_t current_offset, size_t bytes_read, off_t &start, size_t &size)
1314 const int blocksize = 188;
1315 unsigned int max = align(10*1024*1024, blocksize);
1316 current_offset = align(current_offset, blocksize);
1320 eDebug("no cue sheet. forcing normal play");
1321 start = current_offset;
1326 m_cue->m_lock.RdLock();
1327 if (!m_cue->m_decoding_demux)
1329 start = current_offset;
1331 eDebug("getNextSourceSpan, no decoding demux. forcing normal play");
1332 m_cue->m_lock.Unlock();
1338 eDebug("skipmode %d:%d (x%d)", m_skipmode_m, m_skipmode_n, m_skipmode_frames);
1339 max = align(m_skipmode_n, blocksize);
1342 eDebug("getNextSourceSpan, current offset is %08llx, m_skipmode_m = %d!", current_offset, m_skipmode_m);
1344 int frame_skip_success = 0;
1348 int frames_to_skip = m_skipmode_frames + m_skipmode_frames_remainder;
1349 eDebug("we are at %llx, and we try to skip %d+%d frames from here", current_offset, m_skipmode_frames, m_skipmode_frames_remainder);
1351 off_t iframe_start = current_offset;
1352 int frames_skipped = frames_to_skip;
1353 if (!m_tstools.findNextPicture(iframe_start, iframe_len, frames_skipped))
1355 m_skipmode_frames_remainder = frames_to_skip - frames_skipped;
1356 eDebug("successfully skipped %d (out of %d, rem now %d) frames.", frames_skipped, frames_to_skip, m_skipmode_frames_remainder);
1357 current_offset = align_with_len(iframe_start, blocksize, iframe_len);
1358 max = align(iframe_len + 187, blocksize);
1359 frame_skip_success = 1;
1362 m_skipmode_frames_remainder = 0;
1363 eDebug("frame skipping failed, reverting to byte-skipping");
1367 if (!frame_skip_success)
1369 current_offset += align(m_skipmode_m, blocksize);
1373 eDebug("we are at %llx, and we try to find the iframe here:", current_offset);
1375 off_t iframe_start = current_offset;
1377 int direction = (m_skipmode_m < 0) ? -1 : +1;
1378 if (m_tstools.findFrame(iframe_start, iframe_len, direction))
1382 current_offset = align_with_len(iframe_start, blocksize, iframe_len);
1383 max = align(iframe_len, blocksize);
1388 while (!m_cue->m_seek_requests.empty())
1390 std::pair<int, pts_t> seek = m_cue->m_seek_requests.front();
1391 m_cue->m_lock.Unlock();
1392 m_cue->m_lock.WrLock();
1393 m_cue->m_seek_requests.pop_front();
1394 m_cue->m_lock.Unlock();
1395 m_cue->m_lock.RdLock();
1396 int relative = seek.first;
1397 pts_t pts = seek.second;
1402 if (!m_cue->m_decoder)
1404 eDebug("no decoder - can't seek relative");
1407 if (m_cue->m_decoder->getPTS(0, now))
1409 eDebug("decoder getPTS failed, can't seek relative");
1412 if (getCurrentPosition(m_cue->m_decoding_demux, now, 1))
1414 eDebug("seekTo: getCurrentPosition failed!");
1417 } else if (pts < 0) /* seek relative to end */
1420 if (!getLength(len))
1422 eDebug("seeking relative to end. len=%lld, seek = %lld", len, pts);
1426 eWarning("getLength failed - can't seek relative to end!");
1431 if (relative == 1) /* pts relative */
1442 if (relative == 2) /* AP relative */
1444 eDebug("AP relative seeking: %lld, at %lld", pts, now);
1446 if (m_tstools.getNextAccessPoint(nextap, now, pts))
1448 pts = now - 90000; /* approx. 1s */
1449 eDebug("AP relative seeking failed!");
1453 eDebug("next ap is %llx\n", pts);
1458 if (m_tstools.getOffset(offset, pts, -1))
1460 eDebug("get offset for pts=%lld failed!", pts);
1465 /* try to align to iframe */
1466 int direction = pts < 0 ? -1 : 1;
1467 m_tstools.findFrame(offset, iframe_len, direction);
1469 eDebug("ok, resolved skip (rel: %d, diff %lld), now at %08llx (skipped additional %d frames due to iframe re-align)", relative, pts, offset, direction);
1470 current_offset = align(offset, blocksize); /* in case tstools return non-aligned offset */
1473 m_cue->m_lock.Unlock();
1475 for (std::list<std::pair<off_t, off_t> >::const_iterator i(m_source_span.begin()); i != m_source_span.end(); ++i)
1477 long long aligned_start = align(i->first, blocksize);
1478 long long aligned_end = align(i->second, blocksize);
1480 if ((current_offset >= aligned_start) && (current_offset < aligned_end))
1482 start = current_offset;
1483 /* max can not exceed max(size_t). aligned_end - current_offset, however, can. */
1484 if ((aligned_end - current_offset) > max)
1487 size = aligned_end - current_offset;
1488 eDebug("HIT, %lld < %lld < %lld, size: %d", i->first, current_offset, i->second, size);
1491 if (current_offset < aligned_start)
1493 /* ok, our current offset is in an 'out' zone. */
1494 if ((m_skipmode_m >= 0) || (i == m_source_span.begin()))
1496 /* in normal playback, just start at the next zone. */
1499 /* size is not 64bit! */
1500 if ((i->second - i->first) > max)
1503 size = aligned_end - aligned_start;
1506 if (m_skipmode_m < 0)
1508 eDebug("reached SOF");
1511 m_pvr_thread->sendEvent(eFilePushThread::evtUser);
1515 /* when skipping reverse, however, choose the zone before. */
1517 eDebug("skip to previous block, which is %llx..%llx", i->first, i->second);
1520 aligned_start = align(i->first, blocksize);
1521 aligned_end = align(i->second, blocksize);
1523 if ((aligned_end - aligned_start) > max)
1526 len = aligned_end - aligned_start;
1528 start = aligned_end - len;
1529 eDebug("skipping to %llx, %d", start, len);
1532 eDebug("result: %llx, %x (%llx %llx)", start, size, aligned_start, aligned_end);
1537 if ((current_offset < -m_skipmode_m) && (m_skipmode_m < 0))
1539 eDebug("reached SOF");
1541 m_pvr_thread->sendEvent(eFilePushThread::evtUser);
1544 if (m_source_span.empty())
1546 start = current_offset;
1548 eDebug("NO CUESHEET. (%08llx, %d)", start, size);
1551 start = current_offset;
1557 void eDVBChannel::AddUse()
1559 if (++m_use_count > 1 && m_state == state_last_instance)
1562 m_stateChanged(this);
1566 void eDVBChannel::ReleaseUse()
1570 m_state = state_release;
1571 m_stateChanged(this);
1573 else if (m_use_count == 1)
1575 m_state = state_last_instance;
1576 m_stateChanged(this);
1580 RESULT eDVBChannel::setChannel(const eDVBChannelID &channelid, ePtr<iDVBFrontendParameters> &feparm)
1583 m_mgr->removeChannel(this);
1590 eDebug("no frontend to tune!");
1594 m_channel_id = channelid;
1595 m_mgr->addChannel(channelid, this);
1596 m_state = state_tuning;
1597 /* if tuning fails, shutdown the channel immediately. */
1599 res = m_frontend->get().tune(*feparm);
1600 m_current_frontend_parameters = feparm;
1604 m_state = state_release;
1605 m_stateChanged(this);
1612 RESULT eDVBChannel::connectStateChange(const Slot1<void,iDVBChannel*> &stateChange, ePtr<eConnection> &connection)
1614 connection = new eConnection((iDVBChannel*)this, m_stateChanged.connect(stateChange));
1618 RESULT eDVBChannel::connectEvent(const Slot2<void,iDVBChannel*,int> &event, ePtr<eConnection> &connection)
1620 connection = new eConnection((iDVBChannel*)this, m_event.connect(event));
1624 RESULT eDVBChannel::getState(int &state)
1630 RESULT eDVBChannel::setCIRouting(const eDVBCIRouting &routing)
1635 void eDVBChannel::SDTready(int result)
1637 ePyObject args = PyTuple_New(2), ret;
1641 for (std::vector<ServiceDescriptionSection*>::const_iterator i = m_SDT->getSections().begin(); i != m_SDT->getSections().end(); ++i)
1644 PyTuple_SET_ITEM(args, 0, PyInt_FromLong((*i)->getTransportStreamId()));
1645 PyTuple_SET_ITEM(args, 1, PyInt_FromLong((*i)->getOriginalNetworkId()));
1651 PyTuple_SET_ITEM(args, 0, Py_None);
1652 PyTuple_SET_ITEM(args, 1, Py_None);
1656 ret = PyObject_CallObject(m_tsid_onid_callback, args);
1660 Py_DECREF(m_tsid_onid_callback);
1661 m_tsid_onid_callback = ePyObject();
1662 m_tsid_onid_demux = 0;
1666 RESULT eDVBChannel::requestTsidOnid(ePyObject callback)
1668 if (PyCallable_Check(callback))
1670 if (!getDemux(m_tsid_onid_demux, 0))
1672 m_SDT = new eTable<ServiceDescriptionSection>;
1673 CONNECT(m_SDT->tableReady, eDVBChannel::SDTready);
1674 if (m_SDT->start(m_tsid_onid_demux, eDVBSDTSpec()))
1676 m_tsid_onid_demux = 0;
1681 Py_INCREF(callback);
1682 m_tsid_onid_callback = callback;
1690 RESULT eDVBChannel::getDemux(ePtr<iDVBDemux> &demux, int cap)
1692 ePtr<eDVBAllocatedDemux> &our_demux = (cap & capDecode) ? m_decoder_demux : m_demux;
1698 if (m_mgr->allocateDemux(m_frontend ? (eDVBRegisteredFrontend*)*m_frontend : (eDVBRegisteredFrontend*)0, our_demux, cap))
1703 /* don't hold a reference to the decoding demux, we don't need it. */
1705 /* FIXME: by dropping the 'allocated demux' in favour of the 'iDVBDemux',
1706 the refcount is lost. thus, decoding demuxes are never allocated.
1708 this poses a big problem for PiP. */
1710 if (cap & capHoldDecodeReference) // this is set in eDVBResourceManager::allocateDemux for Dm500HD/DM800 and DM8000
1712 else if (cap & capDecode)
1721 RESULT eDVBChannel::getFrontend(ePtr<iDVBFrontend> &frontend)
1726 frontend = &m_frontend->get();
1732 RESULT eDVBChannel::getCurrentFrontendParameters(ePtr<iDVBFrontendParameters> ¶m)
1734 param = m_current_frontend_parameters;
1738 RESULT eDVBChannel::playFile(const char *file)
1740 ASSERT(!m_frontend);
1743 m_pvr_thread->stop();
1744 delete m_pvr_thread;
1748 m_tstools.openFile(file);
1750 /* DON'T EVEN THINK ABOUT FIXING THIS. FIX THE ATI SOURCES FIRST,
1751 THEN DO A REAL FIX HERE! */
1753 /* (this codepath needs to be improved anyway.) */
1754 #if HAVE_DVB_API_VERSION < 3
1755 m_pvr_fd_dst = open("/dev/pvr", O_WRONLY);
1757 m_pvr_fd_dst = open("/dev/misc/pvr", O_WRONLY);
1759 if (m_pvr_fd_dst < 0)
1761 eDebug("can't open /dev/misc/pvr - you need to buy the new(!) $$$ box! (%m)"); // or wait for the driver to be improved.
1765 m_pvr_thread = new eDVBChannelFilePush();
1766 m_pvr_thread->enablePVRCommit(1);
1767 m_pvr_thread->setStreamMode(1);
1768 m_pvr_thread->setScatterGather(this);
1770 if (m_pvr_thread->start(file, m_pvr_fd_dst))
1772 delete m_pvr_thread;
1774 eDebug("can't open PVR file %s (%m)", file);
1777 CONNECT(m_pvr_thread->m_event, eDVBChannel::pvrEvent);
1780 m_stateChanged(this);
1785 void eDVBChannel::stopFile()
1789 m_pvr_thread->stop();
1790 ::close(m_pvr_fd_dst);
1791 delete m_pvr_thread;
1796 void eDVBChannel::setCueSheet(eCueSheet *cuesheet)
1798 m_conn_cueSheetEvent = 0;
1801 m_cue->connectEvent(slot(*this, &eDVBChannel::cueSheetEvent), m_conn_cueSheetEvent);
1804 RESULT eDVBChannel::getLength(pts_t &len)
1806 return m_tstools.calcLen(len);
1809 RESULT eDVBChannel::getCurrentPosition(iDVBDemux *decoding_demux, pts_t &pos, int mode)
1811 if (!decoding_demux)
1818 if (mode == 0) /* demux */
1820 r = decoding_demux->getSTC(now, 0);
1823 eDebug("demux getSTC failed");
1827 now = pos; /* fixup supplied */
1829 off_t off = 0; /* TODO: fixme */
1830 r = m_tstools.fixupPTS(off, now);
1833 eDebug("fixup PTS failed");
1842 void eDVBChannel::flushPVR(iDVBDemux *decoding_demux)
1844 /* when seeking, we have to ensure that all buffers are flushed.
1845 there are basically 3 buffers:
1846 a.) the filepush's internal buffer
1847 b.) the PVR buffer (before demux)
1848 c.) the ratebuffer (after demux)
1850 it's important to clear them in the correct order, otherwise
1851 the ratebuffer (for example) would immediately refill from
1852 the not-yet-flushed PVR buffer.
1855 m_pvr_thread->pause();
1856 /* flush internal filepush buffer */
1857 m_pvr_thread->flush();
1858 /* HACK: flush PVR buffer */
1859 ::ioctl(m_pvr_fd_dst, 0);
1861 /* flush ratebuffers (video, audio) */
1863 decoding_demux->flush();
1865 /* demux will also flush all decoder.. */
1866 /* resume will re-query the SG */
1867 m_pvr_thread->resume();
1870 DEFINE_REF(eCueSheet);
1872 eCueSheet::eCueSheet()
1874 m_skipmode_ratio = 0;
1877 void eCueSheet::seekTo(int relative, const pts_t &pts)
1880 m_seek_requests.push_back(std::pair<int, pts_t>(relative, pts));
1885 void eCueSheet::clear()
1892 void eCueSheet::addSourceSpan(const pts_t &begin, const pts_t &end)
1894 ASSERT(begin < end);
1896 m_spans.push_back(std::pair<pts_t, pts_t>(begin, end));
1900 void eCueSheet::commitSpans()
1902 m_event(evtSpanChanged);
1905 void eCueSheet::setSkipmode(const pts_t &ratio)
1908 m_skipmode_ratio = ratio;
1910 m_event(evtSkipmode);
1913 void eCueSheet::setDecodingDemux(iDVBDemux *demux, iTSMPEGDecoder *decoder)
1915 m_decoding_demux = demux;
1916 m_decoder = decoder;
1919 RESULT eCueSheet::connectEvent(const Slot1<void,int> &event, ePtr<eConnection> &connection)
1921 connection = new eConnection(this, m_event.connect(event));