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;
1129 m_skipmode_n = m_skipmode_m = m_skipmode_frames = 0;
1132 m_frontend->get().connectStateChange(slot(*this, &eDVBChannel::frontendStateChanged), m_conn_frontendStateChanged);
1135 eDVBChannel::~eDVBChannel()
1138 m_mgr->removeChannel(this);
1143 void eDVBChannel::frontendStateChanged(iDVBFrontend*fe)
1145 int state, ourstate = 0;
1147 /* if we are already in shutdown, don't change state. */
1148 if (m_state == state_release)
1151 if (fe->getState(state))
1154 if (state == iDVBFrontend::stateLock)
1156 eDebug("OURSTATE: ok");
1157 ourstate = state_ok;
1158 } else if (state == iDVBFrontend::stateTuning)
1160 eDebug("OURSTATE: tuning");
1161 ourstate = state_tuning;
1162 } else if (state == iDVBFrontend::stateLostLock)
1164 /* on managed channels, we try to retune in order to re-acquire lock. */
1165 if (m_current_frontend_parameters)
1167 eDebug("OURSTATE: lost lock, trying to retune");
1168 ourstate = state_tuning;
1169 m_frontend->get().tune(*m_current_frontend_parameters);
1171 /* on unmanaged channels, we don't do this. the client will do this. */
1173 eDebug("OURSTATE: lost lock, unavailable now.");
1174 ourstate = state_unavailable;
1176 } else if (state == iDVBFrontend::stateFailed)
1178 #ifdef BUILD_VUPLUS /* ikseong */
1179 if (m_current_frontend_parameters)
1181 eDebug("OURSTATE: lost lock, trying to retune");
1182 ourstate = state_tuning;
1183 m_frontend->get().tune(*m_current_frontend_parameters);
1187 eDebug("OURSTATE: failed");
1188 ourstate = state_failed;
1191 eDebug("OURSTATE: failed");
1192 ourstate = state_failed;
1195 eFatal("state unknown");
1197 if (ourstate != m_state)
1200 m_stateChanged(this);
1204 void eDVBChannel::pvrEvent(int event)
1208 case eFilePushThread::evtEOF:
1209 eDebug("eDVBChannel: End of file!");
1210 m_event(this, evtEOF);
1212 case eFilePushThread::evtUser: /* start */
1214 m_event(this, evtSOF);
1219 void eDVBChannel::cueSheetEvent(int event)
1221 /* we might end up here if playing failed or stopped, but the client hasn't (yet) noted. */
1226 case eCueSheet::evtSeek:
1228 flushPVR(m_cue->m_decoding_demux);
1230 case eCueSheet::evtSkipmode:
1233 m_cue->m_lock.WrLock();
1234 m_cue->m_seek_requests.push_back(std::pair<int, pts_t>(1, 0)); /* resync */
1235 m_cue->m_lock.Unlock();
1236 eRdLocker l(m_cue->m_lock);
1237 if (m_cue->m_skipmode_ratio)
1239 int bitrate = m_tstools.calcBitrate(); /* in bits/s */
1240 eDebug("skipmode ratio is %lld:90000, bitrate is %d bit/s", m_cue->m_skipmode_ratio, bitrate);
1241 /* i agree that this might look a bit like black magic. */
1242 m_skipmode_n = 512*1024; /* must be 1 iframe at least. */
1243 m_skipmode_m = bitrate / 8 / 90000 * m_cue->m_skipmode_ratio / 8;
1244 m_skipmode_frames = m_cue->m_skipmode_ratio / 90000;
1245 m_skipmode_frames_remainder = 0;
1247 if (m_cue->m_skipmode_ratio < 0)
1248 m_skipmode_m -= m_skipmode_n;
1250 eDebug("resolved to: %d %d", m_skipmode_m, m_skipmode_n);
1252 if (abs(m_skipmode_m) < abs(m_skipmode_n))
1254 eWarning("something is wrong with this calculation");
1255 m_skipmode_frames = m_skipmode_n = m_skipmode_m = 0;
1259 eDebug("skipmode ratio is 0, normal play");
1260 m_skipmode_frames = m_skipmode_n = m_skipmode_m = 0;
1263 m_pvr_thread->setIFrameSearch(m_skipmode_n != 0);
1264 if (m_cue->m_skipmode_ratio != 0)
1265 m_pvr_thread->setTimebaseChange(0x10000 * 9000 / (m_cue->m_skipmode_ratio / 10)); /* negative values are also ok */
1267 m_pvr_thread->setTimebaseChange(0); /* normal playback */
1268 eDebug("flush pvr");
1269 flushPVR(m_cue->m_decoding_demux);
1273 case eCueSheet::evtSpanChanged:
1275 m_source_span.clear();
1276 for (std::list<std::pair<pts_t, pts_t> >::const_iterator i(m_cue->m_spans.begin()); i != m_cue->m_spans.end(); ++i)
1278 off_t offset_in, offset_out;
1279 pts_t pts_in = i->first, pts_out = i->second;
1280 if (m_tstools.getOffset(offset_in, pts_in, -1) || m_tstools.getOffset(offset_out, pts_out, 1))
1282 eDebug("span translation failed.\n");
1285 eDebug("source span: %llx .. %llx, translated to %llx..%llx", pts_in, pts_out, offset_in, offset_out);
1286 m_source_span.push_back(std::pair<off_t, off_t>(offset_in, offset_out));
1293 /* align toward zero */
1294 static inline long long align(long long x, int align)
1309 /* align toward zero */
1310 static inline long long align_with_len(long long x, int align, size_t &len)
1326 /* remember, this gets called from another thread. */
1327 void eDVBChannel::getNextSourceSpan(off_t current_offset, size_t bytes_read, off_t &start, size_t &size)
1329 const int blocksize = 188;
1330 unsigned int max = align(10*1024*1024, blocksize);
1331 current_offset = align(current_offset, blocksize);
1335 eDebug("no cue sheet. forcing normal play");
1336 start = current_offset;
1343 eDebug("skipmode %d:%d (x%d)", m_skipmode_m, m_skipmode_n, m_skipmode_frames);
1344 max = align(m_skipmode_n, blocksize);
1347 eDebug("getNextSourceSpan, current offset is %08llx, m_skipmode_m = %d!", current_offset, m_skipmode_m);
1348 int frame_skip_success = 0;
1352 int frames_to_skip = m_skipmode_frames + m_skipmode_frames_remainder;
1353 eDebug("we are at %llx, and we try to skip %d+%d frames from here", current_offset, m_skipmode_frames, m_skipmode_frames_remainder);
1355 off_t iframe_start = current_offset;
1356 int frames_skipped = frames_to_skip;
1357 if (!m_tstools.findNextPicture(iframe_start, iframe_len, frames_skipped))
1359 m_skipmode_frames_remainder = frames_to_skip - frames_skipped;
1360 eDebug("successfully skipped %d (out of %d, rem now %d) frames.", frames_skipped, frames_to_skip, m_skipmode_frames_remainder);
1361 current_offset = align_with_len(iframe_start, blocksize, iframe_len);
1362 max = align(iframe_len + 187, blocksize);
1363 frame_skip_success = 1;
1366 m_skipmode_frames_remainder = 0;
1367 eDebug("frame skipping failed, reverting to byte-skipping");
1371 if (!frame_skip_success)
1373 current_offset += align(m_skipmode_m, blocksize);
1377 eDebug("we are at %llx, and we try to find the iframe here:", current_offset);
1379 off_t iframe_start = current_offset;
1381 int direction = (m_skipmode_m < 0) ? -1 : +1;
1382 if (m_tstools.findFrame(iframe_start, iframe_len, direction))
1386 current_offset = align_with_len(iframe_start, blocksize, iframe_len);
1387 max = align(iframe_len, blocksize);
1392 m_cue->m_lock.RdLock();
1394 while (!m_cue->m_seek_requests.empty())
1396 std::pair<int, pts_t> seek = m_cue->m_seek_requests.front();
1397 m_cue->m_lock.Unlock();
1398 m_cue->m_lock.WrLock();
1399 m_cue->m_seek_requests.pop_front();
1400 m_cue->m_lock.Unlock();
1401 m_cue->m_lock.RdLock();
1402 int relative = seek.first;
1403 pts_t pts = seek.second;
1408 if (!m_cue->m_decoder)
1410 eDebug("no decoder - can't seek relative");
1413 if (m_cue->m_decoder->getPTS(0, now))
1415 eDebug("decoder getPTS failed, can't seek relative");
1418 if (!m_cue->m_decoding_demux)
1420 eDebug("getNextSourceSpan, no decoding demux. couldn't seek to %llx... ignore request!", pts);
1421 start = current_offset;
1425 if (getCurrentPosition(m_cue->m_decoding_demux, now, 1))
1427 eDebug("seekTo: getCurrentPosition failed!");
1430 } else if (pts < 0) /* seek relative to end */
1433 if (!getLength(len))
1435 eDebug("seeking relative to end. len=%lld, seek = %lld", len, pts);
1439 eWarning("getLength failed - can't seek relative to end!");
1444 if (relative == 1) /* pts relative */
1455 if (relative == 2) /* AP relative */
1457 eDebug("AP relative seeking: %lld, at %lld", pts, now);
1459 if (m_tstools.getNextAccessPoint(nextap, now, pts))
1461 pts = now - 90000; /* approx. 1s */
1462 eDebug("AP relative seeking failed!");
1466 eDebug("next ap is %llx\n", pts);
1471 if (m_tstools.getOffset(offset, pts, -1))
1473 eDebug("get offset for pts=%lld failed!", pts);
1477 eDebug("ok, resolved skip (rel: %d, diff %lld), now at %08llx", relative, pts, offset);
1478 current_offset = align(offset, blocksize); /* in case tstools return non-aligned offset */
1481 m_cue->m_lock.Unlock();
1483 for (std::list<std::pair<off_t, off_t> >::const_iterator i(m_source_span.begin()); i != m_source_span.end(); ++i)
1485 long long aligned_start = align(i->first, blocksize);
1486 long long aligned_end = align(i->second, blocksize);
1488 if ((current_offset >= aligned_start) && (current_offset < aligned_end))
1490 start = current_offset;
1491 /* max can not exceed max(size_t). aligned_end - current_offset, however, can. */
1492 if ((aligned_end - current_offset) > max)
1495 size = aligned_end - current_offset;
1496 eDebug("HIT, %lld < %lld < %lld, size: %d", i->first, current_offset, i->second, size);
1499 if (current_offset < aligned_start)
1501 /* ok, our current offset is in an 'out' zone. */
1502 if ((m_skipmode_m >= 0) || (i == m_source_span.begin()))
1504 /* in normal playback, just start at the next zone. */
1507 /* size is not 64bit! */
1508 if ((i->second - i->first) > max)
1511 size = aligned_end - aligned_start;
1514 if (m_skipmode_m < 0)
1516 eDebug("reached SOF");
1519 m_pvr_thread->sendEvent(eFilePushThread::evtUser);
1523 /* when skipping reverse, however, choose the zone before. */
1525 eDebug("skip to previous block, which is %llx..%llx", i->first, i->second);
1528 aligned_start = align(i->first, blocksize);
1529 aligned_end = align(i->second, blocksize);
1531 if ((aligned_end - aligned_start) > max)
1534 len = aligned_end - aligned_start;
1536 start = aligned_end - len;
1537 eDebug("skipping to %llx, %d", start, len);
1540 eDebug("result: %llx, %x (%llx %llx)", start, size, aligned_start, aligned_end);
1545 if ((current_offset < -m_skipmode_m) && (m_skipmode_m < 0))
1547 eDebug("reached SOF");
1549 m_pvr_thread->sendEvent(eFilePushThread::evtUser);
1552 if (m_source_span.empty())
1554 start = current_offset;
1556 eDebug("NO CUESHEET. (%08llx, %d)", start, size);
1559 start = current_offset;
1565 void eDVBChannel::AddUse()
1567 if (++m_use_count > 1 && m_state == state_last_instance)
1570 m_stateChanged(this);
1574 void eDVBChannel::ReleaseUse()
1578 m_state = state_release;
1579 m_stateChanged(this);
1581 else if (m_use_count == 1)
1583 m_state = state_last_instance;
1584 m_stateChanged(this);
1588 RESULT eDVBChannel::setChannel(const eDVBChannelID &channelid, ePtr<iDVBFrontendParameters> &feparm)
1591 m_mgr->removeChannel(this);
1598 eDebug("no frontend to tune!");
1602 m_channel_id = channelid;
1603 m_mgr->addChannel(channelid, this);
1604 m_state = state_tuning;
1605 /* if tuning fails, shutdown the channel immediately. */
1607 res = m_frontend->get().tune(*feparm);
1608 m_current_frontend_parameters = feparm;
1612 m_state = state_release;
1613 m_stateChanged(this);
1620 RESULT eDVBChannel::connectStateChange(const Slot1<void,iDVBChannel*> &stateChange, ePtr<eConnection> &connection)
1622 connection = new eConnection((iDVBChannel*)this, m_stateChanged.connect(stateChange));
1626 RESULT eDVBChannel::connectEvent(const Slot2<void,iDVBChannel*,int> &event, ePtr<eConnection> &connection)
1628 connection = new eConnection((iDVBChannel*)this, m_event.connect(event));
1632 RESULT eDVBChannel::getState(int &state)
1638 RESULT eDVBChannel::setCIRouting(const eDVBCIRouting &routing)
1643 void eDVBChannel::SDTready(int result)
1645 ePyObject args = PyTuple_New(2), ret;
1649 for (std::vector<ServiceDescriptionSection*>::const_iterator i = m_SDT->getSections().begin(); i != m_SDT->getSections().end(); ++i)
1652 PyTuple_SET_ITEM(args, 0, PyInt_FromLong((*i)->getTransportStreamId()));
1653 PyTuple_SET_ITEM(args, 1, PyInt_FromLong((*i)->getOriginalNetworkId()));
1659 PyTuple_SET_ITEM(args, 0, Py_None);
1660 PyTuple_SET_ITEM(args, 1, Py_None);
1664 ret = PyObject_CallObject(m_tsid_onid_callback, args);
1668 Py_DECREF(m_tsid_onid_callback);
1669 m_tsid_onid_callback = ePyObject();
1670 m_tsid_onid_demux = 0;
1674 RESULT eDVBChannel::requestTsidOnid(ePyObject callback)
1676 if (PyCallable_Check(callback))
1678 if (!getDemux(m_tsid_onid_demux, 0))
1680 m_SDT = new eTable<ServiceDescriptionSection>;
1681 CONNECT(m_SDT->tableReady, eDVBChannel::SDTready);
1682 if (m_SDT->start(m_tsid_onid_demux, eDVBSDTSpec()))
1684 m_tsid_onid_demux = 0;
1689 Py_INCREF(callback);
1690 m_tsid_onid_callback = callback;
1698 RESULT eDVBChannel::getDemux(ePtr<iDVBDemux> &demux, int cap)
1700 ePtr<eDVBAllocatedDemux> &our_demux = (cap & capDecode) ? m_decoder_demux : m_demux;
1706 if (m_mgr->allocateDemux(m_frontend ? (eDVBRegisteredFrontend*)*m_frontend : (eDVBRegisteredFrontend*)0, our_demux, cap))
1711 /* don't hold a reference to the decoding demux, we don't need it. */
1713 /* FIXME: by dropping the 'allocated demux' in favour of the 'iDVBDemux',
1714 the refcount is lost. thus, decoding demuxes are never allocated.
1716 this poses a big problem for PiP. */
1718 if (cap & capHoldDecodeReference) // this is set in eDVBResourceManager::allocateDemux for Dm500HD/DM800 and DM8000
1720 else if (cap & capDecode)
1729 RESULT eDVBChannel::getFrontend(ePtr<iDVBFrontend> &frontend)
1734 frontend = &m_frontend->get();
1740 RESULT eDVBChannel::getCurrentFrontendParameters(ePtr<iDVBFrontendParameters> ¶m)
1742 param = m_current_frontend_parameters;
1746 RESULT eDVBChannel::playFile(const char *file)
1748 ASSERT(!m_frontend);
1751 m_pvr_thread->stop();
1752 delete m_pvr_thread;
1756 m_tstools.openFile(file);
1758 /* DON'T EVEN THINK ABOUT FIXING THIS. FIX THE ATI SOURCES FIRST,
1759 THEN DO A REAL FIX HERE! */
1761 if (m_pvr_fd_dst < 0)
1763 /* (this codepath needs to be improved anyway.) */
1764 #if HAVE_DVB_API_VERSION < 3
1765 m_pvr_fd_dst = open("/dev/pvr", O_WRONLY);
1767 m_pvr_fd_dst = open("/dev/misc/pvr", O_WRONLY);
1769 if (m_pvr_fd_dst < 0)
1771 eDebug("can't open /dev/misc/pvr - you need to buy the new(!) $$$ box! (%m)"); // or wait for the driver to be improved.
1776 m_pvr_thread = new eDVBChannelFilePush();
1777 m_pvr_thread->enablePVRCommit(1);
1778 m_pvr_thread->setStreamMode(1);
1779 m_pvr_thread->setScatterGather(this);
1781 m_event(this, evtPreStart);
1783 if (m_pvr_thread->start(file, m_pvr_fd_dst))
1785 delete m_pvr_thread;
1787 ::close(m_pvr_fd_dst);
1789 eDebug("can't open PVR file %s (%m)", file);
1792 CONNECT(m_pvr_thread->m_event, eDVBChannel::pvrEvent);
1795 m_stateChanged(this);
1800 void eDVBChannel::stopFile()
1804 m_pvr_thread->stop();
1805 delete m_pvr_thread;
1808 if (m_pvr_fd_dst >= 0)
1809 ::close(m_pvr_fd_dst);
1812 void eDVBChannel::setCueSheet(eCueSheet *cuesheet)
1814 m_conn_cueSheetEvent = 0;
1817 m_cue->connectEvent(slot(*this, &eDVBChannel::cueSheetEvent), m_conn_cueSheetEvent);
1820 RESULT eDVBChannel::getLength(pts_t &len)
1822 return m_tstools.calcLen(len);
1825 RESULT eDVBChannel::getCurrentPosition(iDVBDemux *decoding_demux, pts_t &pos, int mode)
1827 if (!decoding_demux)
1834 if (mode == 0) /* demux */
1836 r = decoding_demux->getSTC(now, 0);
1839 eDebug("demux getSTC failed");
1843 now = pos; /* fixup supplied */
1845 off_t off = 0; /* TODO: fixme */
1846 r = m_tstools.fixupPTS(off, now);
1849 eDebug("fixup PTS failed");
1858 void eDVBChannel::flushPVR(iDVBDemux *decoding_demux)
1860 /* when seeking, we have to ensure that all buffers are flushed.
1861 there are basically 3 buffers:
1862 a.) the filepush's internal buffer
1863 b.) the PVR buffer (before demux)
1864 c.) the ratebuffer (after demux)
1866 it's important to clear them in the correct order, otherwise
1867 the ratebuffer (for example) would immediately refill from
1868 the not-yet-flushed PVR buffer.
1871 m_pvr_thread->pause();
1872 /* flush internal filepush buffer */
1873 m_pvr_thread->flush();
1874 /* HACK: flush PVR buffer */
1875 ::ioctl(m_pvr_fd_dst, 0);
1877 /* flush ratebuffers (video, audio) */
1879 decoding_demux->flush();
1881 /* demux will also flush all decoder.. */
1882 /* resume will re-query the SG */
1883 m_pvr_thread->resume();
1886 DEFINE_REF(eCueSheet);
1888 eCueSheet::eCueSheet()
1890 m_skipmode_ratio = 0;
1893 void eCueSheet::seekTo(int relative, const pts_t &pts)
1896 m_seek_requests.push_back(std::pair<int, pts_t>(relative, pts));
1901 void eCueSheet::clear()
1908 void eCueSheet::addSourceSpan(const pts_t &begin, const pts_t &end)
1910 ASSERT(begin < end);
1912 m_spans.push_back(std::pair<pts_t, pts_t>(begin, end));
1916 void eCueSheet::commitSpans()
1918 m_event(evtSpanChanged);
1921 void eCueSheet::setSkipmode(const pts_t &ratio)
1924 m_skipmode_ratio = ratio;
1926 m_event(evtSkipmode);
1929 void eCueSheet::setDecodingDemux(iDVBDemux *demux, iTSMPEGDecoder *decoder)
1931 m_decoding_demux = demux;
1932 m_decoder = decoder;
1935 RESULT eCueSheet::connectEvent(const Slot1<void,int> &event, ePtr<eConnection> &connection)
1937 connection = new eConnection(this, m_event.connect(event));