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 eDebug("OURSTATE: failed");
1179 ourstate = state_failed;
1181 eFatal("state unknown");
1183 if (ourstate != m_state)
1186 m_stateChanged(this);
1190 void eDVBChannel::pvrEvent(int event)
1194 case eFilePushThread::evtEOF:
1195 eDebug("eDVBChannel: End of file!");
1196 m_event(this, evtEOF);
1198 case eFilePushThread::evtUser: /* start */
1200 m_event(this, evtSOF);
1205 void eDVBChannel::cueSheetEvent(int event)
1207 /* we might end up here if playing failed or stopped, but the client hasn't (yet) noted. */
1212 case eCueSheet::evtSeek:
1214 flushPVR(m_cue->m_decoding_demux);
1216 case eCueSheet::evtSkipmode:
1219 m_cue->m_lock.WrLock();
1220 m_cue->m_seek_requests.push_back(std::pair<int, pts_t>(1, 0)); /* resync */
1221 m_cue->m_lock.Unlock();
1222 eRdLocker l(m_cue->m_lock);
1223 if (m_cue->m_skipmode_ratio)
1225 int bitrate = m_tstools.calcBitrate(); /* in bits/s */
1226 eDebug("skipmode ratio is %lld:90000, bitrate is %d bit/s", m_cue->m_skipmode_ratio, bitrate);
1227 /* i agree that this might look a bit like black magic. */
1228 m_skipmode_n = 512*1024; /* must be 1 iframe at least. */
1229 m_skipmode_m = bitrate / 8 / 90000 * m_cue->m_skipmode_ratio / 8;
1230 m_skipmode_frames = m_cue->m_skipmode_ratio / 90000;
1231 m_skipmode_frames_remainder = 0;
1233 if (m_cue->m_skipmode_ratio < 0)
1234 m_skipmode_m -= m_skipmode_n;
1236 eDebug("resolved to: %d %d", m_skipmode_m, m_skipmode_n);
1238 if (abs(m_skipmode_m) < abs(m_skipmode_n))
1240 eWarning("something is wrong with this calculation");
1241 m_skipmode_frames = m_skipmode_n = m_skipmode_m = 0;
1245 eDebug("skipmode ratio is 0, normal play");
1246 m_skipmode_frames = m_skipmode_n = m_skipmode_m = 0;
1249 m_pvr_thread->setIFrameSearch(m_skipmode_n != 0);
1250 if (m_cue->m_skipmode_ratio != 0)
1251 m_pvr_thread->setTimebaseChange(0x10000 * 9000 / (m_cue->m_skipmode_ratio / 10)); /* negative values are also ok */
1253 m_pvr_thread->setTimebaseChange(0); /* normal playback */
1254 eDebug("flush pvr");
1255 flushPVR(m_cue->m_decoding_demux);
1259 case eCueSheet::evtSpanChanged:
1261 m_source_span.clear();
1262 for (std::list<std::pair<pts_t, pts_t> >::const_iterator i(m_cue->m_spans.begin()); i != m_cue->m_spans.end(); ++i)
1264 off_t offset_in, offset_out;
1265 pts_t pts_in = i->first, pts_out = i->second;
1266 if (m_tstools.getOffset(offset_in, pts_in, -1) || m_tstools.getOffset(offset_out, pts_out, 1))
1268 eDebug("span translation failed.\n");
1271 eDebug("source span: %llx .. %llx, translated to %llx..%llx", pts_in, pts_out, offset_in, offset_out);
1272 m_source_span.push_back(std::pair<off_t, off_t>(offset_in, offset_out));
1279 /* align toward zero */
1280 static inline long long align(long long x, int align)
1295 /* align toward zero */
1296 static inline long long align_with_len(long long x, int align, size_t &len)
1312 /* remember, this gets called from another thread. */
1313 void eDVBChannel::getNextSourceSpan(off_t current_offset, size_t bytes_read, off_t &start, size_t &size)
1315 const int blocksize = 188;
1316 unsigned int max = align(10*1024*1024, blocksize);
1317 current_offset = align(current_offset, blocksize);
1321 eDebug("no cue sheet. forcing normal play");
1322 start = current_offset;
1327 m_cue->m_lock.RdLock();
1328 if (!m_cue->m_decoding_demux)
1330 start = current_offset;
1332 eDebug("getNextSourceSpan, no decoding demux. forcing normal play");
1333 m_cue->m_lock.Unlock();
1339 eDebug("skipmode %d:%d (x%d)", m_skipmode_m, m_skipmode_n, m_skipmode_frames);
1340 max = align(m_skipmode_n, blocksize);
1343 eDebug("getNextSourceSpan, current offset is %08llx, m_skipmode_m = %d!", current_offset, m_skipmode_m);
1345 int frame_skip_success = 0;
1349 int frames_to_skip = m_skipmode_frames + m_skipmode_frames_remainder;
1350 eDebug("we are at %llx, and we try to skip %d+%d frames from here", current_offset, m_skipmode_frames, m_skipmode_frames_remainder);
1352 off_t iframe_start = current_offset;
1353 int frames_skipped = frames_to_skip;
1354 if (!m_tstools.findNextPicture(iframe_start, iframe_len, frames_skipped))
1356 m_skipmode_frames_remainder = frames_to_skip - frames_skipped;
1357 eDebug("successfully skipped %d (out of %d, rem now %d) frames.", frames_skipped, frames_to_skip, m_skipmode_frames_remainder);
1358 current_offset = align_with_len(iframe_start, blocksize, iframe_len);
1359 max = align(iframe_len + 187, blocksize);
1360 frame_skip_success = 1;
1363 m_skipmode_frames_remainder = 0;
1364 eDebug("frame skipping failed, reverting to byte-skipping");
1368 if (!frame_skip_success)
1370 current_offset += align(m_skipmode_m, blocksize);
1374 eDebug("we are at %llx, and we try to find the iframe here:", current_offset);
1376 off_t iframe_start = current_offset;
1378 int direction = (m_skipmode_m < 0) ? -1 : +1;
1379 if (m_tstools.findFrame(iframe_start, iframe_len, direction))
1383 current_offset = align_with_len(iframe_start, blocksize, iframe_len);
1384 max = align(iframe_len, blocksize);
1389 while (!m_cue->m_seek_requests.empty())
1391 std::pair<int, pts_t> seek = m_cue->m_seek_requests.front();
1392 m_cue->m_lock.Unlock();
1393 m_cue->m_lock.WrLock();
1394 m_cue->m_seek_requests.pop_front();
1395 m_cue->m_lock.Unlock();
1396 m_cue->m_lock.RdLock();
1397 int relative = seek.first;
1398 pts_t pts = seek.second;
1403 if (!m_cue->m_decoder)
1405 eDebug("no decoder - can't seek relative");
1408 if (m_cue->m_decoder->getPTS(0, now))
1410 eDebug("decoder getPTS failed, can't seek relative");
1413 if (getCurrentPosition(m_cue->m_decoding_demux, now, 1))
1415 eDebug("seekTo: getCurrentPosition failed!");
1418 } else if (pts < 0) /* seek relative to end */
1421 if (!getLength(len))
1423 eDebug("seeking relative to end. len=%lld, seek = %lld", len, pts);
1427 eWarning("getLength failed - can't seek relative to end!");
1432 if (relative == 1) /* pts relative */
1443 if (relative == 2) /* AP relative */
1445 eDebug("AP relative seeking: %lld, at %lld", pts, now);
1447 if (m_tstools.getNextAccessPoint(nextap, now, pts))
1449 pts = now - 90000; /* approx. 1s */
1450 eDebug("AP relative seeking failed!");
1454 eDebug("next ap is %llx\n", pts);
1459 if (m_tstools.getOffset(offset, pts, -1))
1461 eDebug("get offset for pts=%lld failed!", pts);
1466 /* try to align to iframe */
1467 int direction = pts < 0 ? -1 : 1;
1468 m_tstools.findFrame(offset, iframe_len, direction);
1470 eDebug("ok, resolved skip (rel: %d, diff %lld), now at %08llx (skipped additional %d frames due to iframe re-align)", relative, pts, offset, direction);
1471 current_offset = align(offset, blocksize); /* in case tstools return non-aligned offset */
1474 m_cue->m_lock.Unlock();
1476 for (std::list<std::pair<off_t, off_t> >::const_iterator i(m_source_span.begin()); i != m_source_span.end(); ++i)
1478 long long aligned_start = align(i->first, blocksize);
1479 long long aligned_end = align(i->second, blocksize);
1481 if ((current_offset >= aligned_start) && (current_offset < aligned_end))
1483 start = current_offset;
1484 /* max can not exceed max(size_t). aligned_end - current_offset, however, can. */
1485 if ((aligned_end - current_offset) > max)
1488 size = aligned_end - current_offset;
1489 eDebug("HIT, %lld < %lld < %lld, size: %d", i->first, current_offset, i->second, size);
1492 if (current_offset < aligned_start)
1494 /* ok, our current offset is in an 'out' zone. */
1495 if ((m_skipmode_m >= 0) || (i == m_source_span.begin()))
1497 /* in normal playback, just start at the next zone. */
1500 /* size is not 64bit! */
1501 if ((i->second - i->first) > max)
1504 size = aligned_end - aligned_start;
1507 if (m_skipmode_m < 0)
1509 eDebug("reached SOF");
1512 m_pvr_thread->sendEvent(eFilePushThread::evtUser);
1516 /* when skipping reverse, however, choose the zone before. */
1518 eDebug("skip to previous block, which is %llx..%llx", i->first, i->second);
1521 aligned_start = align(i->first, blocksize);
1522 aligned_end = align(i->second, blocksize);
1524 if ((aligned_end - aligned_start) > max)
1527 len = aligned_end - aligned_start;
1529 start = aligned_end - len;
1530 eDebug("skipping to %llx, %d", start, len);
1533 eDebug("result: %llx, %x (%llx %llx)", start, size, aligned_start, aligned_end);
1538 if ((current_offset < -m_skipmode_m) && (m_skipmode_m < 0))
1540 eDebug("reached SOF");
1542 m_pvr_thread->sendEvent(eFilePushThread::evtUser);
1545 if (m_source_span.empty())
1547 start = current_offset;
1549 eDebug("NO CUESHEET. (%08llx, %d)", start, size);
1552 start = current_offset;
1558 void eDVBChannel::AddUse()
1560 if (++m_use_count > 1 && m_state == state_last_instance)
1563 m_stateChanged(this);
1567 void eDVBChannel::ReleaseUse()
1571 m_state = state_release;
1572 m_stateChanged(this);
1574 else if (m_use_count == 1)
1576 m_state = state_last_instance;
1577 m_stateChanged(this);
1581 RESULT eDVBChannel::setChannel(const eDVBChannelID &channelid, ePtr<iDVBFrontendParameters> &feparm)
1584 m_mgr->removeChannel(this);
1591 eDebug("no frontend to tune!");
1595 m_channel_id = channelid;
1596 m_mgr->addChannel(channelid, this);
1597 m_state = state_tuning;
1598 /* if tuning fails, shutdown the channel immediately. */
1600 res = m_frontend->get().tune(*feparm);
1601 m_current_frontend_parameters = feparm;
1605 m_state = state_release;
1606 m_stateChanged(this);
1613 RESULT eDVBChannel::connectStateChange(const Slot1<void,iDVBChannel*> &stateChange, ePtr<eConnection> &connection)
1615 connection = new eConnection((iDVBChannel*)this, m_stateChanged.connect(stateChange));
1619 RESULT eDVBChannel::connectEvent(const Slot2<void,iDVBChannel*,int> &event, ePtr<eConnection> &connection)
1621 connection = new eConnection((iDVBChannel*)this, m_event.connect(event));
1625 RESULT eDVBChannel::getState(int &state)
1631 RESULT eDVBChannel::setCIRouting(const eDVBCIRouting &routing)
1636 void eDVBChannel::SDTready(int result)
1638 ePyObject args = PyTuple_New(2), ret;
1642 for (std::vector<ServiceDescriptionSection*>::const_iterator i = m_SDT->getSections().begin(); i != m_SDT->getSections().end(); ++i)
1645 PyTuple_SET_ITEM(args, 0, PyInt_FromLong((*i)->getTransportStreamId()));
1646 PyTuple_SET_ITEM(args, 1, PyInt_FromLong((*i)->getOriginalNetworkId()));
1652 PyTuple_SET_ITEM(args, 0, Py_None);
1653 PyTuple_SET_ITEM(args, 1, Py_None);
1657 ret = PyObject_CallObject(m_tsid_onid_callback, args);
1661 Py_DECREF(m_tsid_onid_callback);
1662 m_tsid_onid_callback = ePyObject();
1663 m_tsid_onid_demux = 0;
1667 RESULT eDVBChannel::requestTsidOnid(ePyObject callback)
1669 if (PyCallable_Check(callback))
1671 if (!getDemux(m_tsid_onid_demux, 0))
1673 m_SDT = new eTable<ServiceDescriptionSection>;
1674 CONNECT(m_SDT->tableReady, eDVBChannel::SDTready);
1675 if (m_SDT->start(m_tsid_onid_demux, eDVBSDTSpec()))
1677 m_tsid_onid_demux = 0;
1682 Py_INCREF(callback);
1683 m_tsid_onid_callback = callback;
1691 RESULT eDVBChannel::getDemux(ePtr<iDVBDemux> &demux, int cap)
1693 ePtr<eDVBAllocatedDemux> &our_demux = (cap & capDecode) ? m_decoder_demux : m_demux;
1699 if (m_mgr->allocateDemux(m_frontend ? (eDVBRegisteredFrontend*)*m_frontend : (eDVBRegisteredFrontend*)0, our_demux, cap))
1704 /* don't hold a reference to the decoding demux, we don't need it. */
1706 /* FIXME: by dropping the 'allocated demux' in favour of the 'iDVBDemux',
1707 the refcount is lost. thus, decoding demuxes are never allocated.
1709 this poses a big problem for PiP. */
1711 if (cap & capHoldDecodeReference) // this is set in eDVBResourceManager::allocateDemux for Dm500HD/DM800 and DM8000
1713 else if (cap & capDecode)
1722 RESULT eDVBChannel::getFrontend(ePtr<iDVBFrontend> &frontend)
1727 frontend = &m_frontend->get();
1733 RESULT eDVBChannel::getCurrentFrontendParameters(ePtr<iDVBFrontendParameters> ¶m)
1735 param = m_current_frontend_parameters;
1739 RESULT eDVBChannel::playFile(const char *file)
1741 ASSERT(!m_frontend);
1744 m_pvr_thread->stop();
1745 delete m_pvr_thread;
1749 m_tstools.openFile(file);
1751 /* DON'T EVEN THINK ABOUT FIXING THIS. FIX THE ATI SOURCES FIRST,
1752 THEN DO A REAL FIX HERE! */
1754 if (m_pvr_fd_dst < 0)
1756 /* (this codepath needs to be improved anyway.) */
1757 #if HAVE_DVB_API_VERSION < 3
1758 m_pvr_fd_dst = open("/dev/pvr", O_WRONLY);
1760 m_pvr_fd_dst = open("/dev/misc/pvr", O_WRONLY);
1762 if (m_pvr_fd_dst < 0)
1764 eDebug("can't open /dev/misc/pvr - you need to buy the new(!) $$$ box! (%m)"); // or wait for the driver to be improved.
1769 m_pvr_thread = new eDVBChannelFilePush();
1770 m_pvr_thread->enablePVRCommit(1);
1771 m_pvr_thread->setStreamMode(1);
1772 m_pvr_thread->setScatterGather(this);
1774 if (m_pvr_thread->start(file, m_pvr_fd_dst))
1776 delete m_pvr_thread;
1778 ::close(m_pvr_fd_dst);
1780 eDebug("can't open PVR file %s (%m)", file);
1783 CONNECT(m_pvr_thread->m_event, eDVBChannel::pvrEvent);
1786 m_stateChanged(this);
1791 void eDVBChannel::stopFile()
1795 m_pvr_thread->stop();
1796 delete m_pvr_thread;
1799 if (m_pvr_fd_dst >= 0)
1800 ::close(m_pvr_fd_dst);
1803 void eDVBChannel::setCueSheet(eCueSheet *cuesheet)
1805 m_conn_cueSheetEvent = 0;
1808 m_cue->connectEvent(slot(*this, &eDVBChannel::cueSheetEvent), m_conn_cueSheetEvent);
1811 RESULT eDVBChannel::getLength(pts_t &len)
1813 return m_tstools.calcLen(len);
1816 RESULT eDVBChannel::getCurrentPosition(iDVBDemux *decoding_demux, pts_t &pos, int mode)
1818 if (!decoding_demux)
1825 if (mode == 0) /* demux */
1827 r = decoding_demux->getSTC(now, 0);
1830 eDebug("demux getSTC failed");
1834 now = pos; /* fixup supplied */
1836 off_t off = 0; /* TODO: fixme */
1837 r = m_tstools.fixupPTS(off, now);
1840 eDebug("fixup PTS failed");
1849 void eDVBChannel::flushPVR(iDVBDemux *decoding_demux)
1851 /* when seeking, we have to ensure that all buffers are flushed.
1852 there are basically 3 buffers:
1853 a.) the filepush's internal buffer
1854 b.) the PVR buffer (before demux)
1855 c.) the ratebuffer (after demux)
1857 it's important to clear them in the correct order, otherwise
1858 the ratebuffer (for example) would immediately refill from
1859 the not-yet-flushed PVR buffer.
1862 m_pvr_thread->pause();
1863 /* flush internal filepush buffer */
1864 m_pvr_thread->flush();
1865 /* HACK: flush PVR buffer */
1866 ::ioctl(m_pvr_fd_dst, 0);
1868 /* flush ratebuffers (video, audio) */
1870 decoding_demux->flush();
1872 /* demux will also flush all decoder.. */
1873 /* resume will re-query the SG */
1874 m_pvr_thread->resume();
1877 DEFINE_REF(eCueSheet);
1879 eCueSheet::eCueSheet()
1881 m_skipmode_ratio = 0;
1884 void eCueSheet::seekTo(int relative, const pts_t &pts)
1887 m_seek_requests.push_back(std::pair<int, pts_t>(relative, pts));
1892 void eCueSheet::clear()
1899 void eCueSheet::addSourceSpan(const pts_t &begin, const pts_t &end)
1901 ASSERT(begin < end);
1903 m_spans.push_back(std::pair<pts_t, pts_t>(begin, end));
1907 void eCueSheet::commitSpans()
1909 m_event(evtSpanChanged);
1912 void eCueSheet::setSkipmode(const pts_t &ratio)
1915 m_skipmode_ratio = ratio;
1917 m_event(evtSkipmode);
1920 void eCueSheet::setDecodingDemux(iDVBDemux *demux, iTSMPEGDecoder *decoder)
1922 m_decoding_demux = demux;
1923 m_decoder = decoder;
1926 RESULT eCueSheet::connectEvent(const Slot1<void,int> &event, ePtr<eConnection> &connection)
1928 connection = new eConnection(this, m_event.connect(event));