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))
99 else if (!strncmp(tmp, "dm800se\n", rd))
102 eDebug("boxtype detection via /proc/stb/info not possible... use fallback via demux count!\n");
103 if (m_demux.size() == 3)
105 else if (m_demux.size() < 5)
111 eDebug("found %d adapter, %d frontends(%d sim) and %d demux, boxtype %d",
112 m_adapter.size(), m_frontend.size(), m_simulate_frontend.size(), m_demux.size(), m_boxtype);
114 eDVBCAService::registerChannelCallback(this);
116 CONNECT(m_releaseCachedChannelTimer->timeout, eDVBResourceManager::releaseCachedChannel);
119 void eDVBResourceManager::feStateChanged()
122 for (eSmartPtrList<eDVBRegisteredFrontend>::iterator i(m_frontend.begin()); i != m_frontend.end(); ++i)
124 mask |= ( 1 << i->m_frontend->getSlotID() );
125 /* emit */ frontendUseMaskChanged(mask);
128 DEFINE_REF(eDVBAdapterLinux);
129 eDVBAdapterLinux::eDVBAdapterLinux(int nr): m_nr(nr)
134 eDebug("scanning for frontends..");
139 #if HAVE_DVB_API_VERSION < 3
140 sprintf(filename, "/dev/dvb/card%d/frontend%d", m_nr, num_fe);
142 sprintf(filename, "/dev/dvb/adapter%d/frontend%d", m_nr, num_fe);
144 if (stat(filename, &s))
146 ePtr<eDVBFrontend> fe;
150 fe = new eDVBFrontend(m_nr, num_fe, ok);
152 m_frontend.push_back(fe);
156 fe = new eDVBFrontend(m_nr, num_fe, ok, true);
158 m_simulate_frontend.push_back(fe);
169 #if HAVE_DVB_API_VERSION < 3
170 sprintf(filename, "/dev/dvb/card%d/demux%d", m_nr, num_demux);
172 sprintf(filename, "/dev/dvb/adapter%d/demux%d", m_nr, num_demux);
174 if (stat(filename, &s))
176 ePtr<eDVBDemux> demux;
178 demux = new eDVBDemux(m_nr, num_demux);
179 m_demux.push_back(demux);
185 int eDVBAdapterLinux::getNumDemux()
187 return m_demux.size();
190 RESULT eDVBAdapterLinux::getDemux(ePtr<eDVBDemux> &demux, int nr)
192 eSmartPtrList<eDVBDemux>::iterator i(m_demux.begin());
193 while (nr && (i != m_demux.end()))
199 if (i != m_demux.end())
207 int eDVBAdapterLinux::getNumFrontends()
209 return m_frontend.size();
212 RESULT eDVBAdapterLinux::getFrontend(ePtr<eDVBFrontend> &fe, int nr, bool simulate)
214 eSmartPtrList<eDVBFrontend>::iterator i(simulate ? m_simulate_frontend.begin() : m_frontend.begin());
215 while (nr && (i != m_frontend.end()))
221 if (i != m_frontend.end())
229 int eDVBAdapterLinux::exist(int nr)
233 #if HAVE_DVB_API_VERSION < 3
234 sprintf(filename, "/dev/dvb/card%d", nr);
236 sprintf(filename, "/dev/dvb/adapter%d", nr);
238 if (!stat(filename, &s))
243 eDVBResourceManager::~eDVBResourceManager()
245 if (instance == this)
249 void eDVBResourceManager::addAdapter(iDVBAdapter *adapter)
251 int num_fe = adapter->getNumFrontends();
252 int num_demux = adapter->getNumDemux();
254 m_adapter.push_back(adapter);
257 for (i=0; i<num_demux; ++i)
259 ePtr<eDVBDemux> demux;
260 if (!adapter->getDemux(demux, i))
261 m_demux.push_back(new eDVBRegisteredDemux(demux, adapter));
264 ePtr<eDVBRegisteredFrontend> prev_dvbt_frontend;
265 for (i=0; i<num_fe; ++i)
267 ePtr<eDVBFrontend> frontend;
268 if (!adapter->getFrontend(frontend, i))
271 frontend->getFrontendType(frontendType);
272 eDVBRegisteredFrontend *new_fe = new eDVBRegisteredFrontend(frontend, adapter);
273 CONNECT(new_fe->stateChanged, eDVBResourceManager::feStateChanged);
274 m_frontend.push_back(new_fe);
275 frontend->setSEC(m_sec);
276 // we must link all dvb-t frontends ( for active antenna voltage )
277 if (frontendType == iDVBFrontend::feTerrestrial)
279 if (prev_dvbt_frontend)
281 prev_dvbt_frontend->m_frontend->setData(eDVBFrontend::LINKED_NEXT_PTR, (long)new_fe);
282 frontend->setData(eDVBFrontend::LINKED_PREV_PTR, (long)&(*prev_dvbt_frontend));
284 prev_dvbt_frontend = new_fe;
289 prev_dvbt_frontend = 0;
290 for (i=0; i<num_fe; ++i)
292 ePtr<eDVBFrontend> frontend;
293 if (!adapter->getFrontend(frontend, i, true))
296 frontend->getFrontendType(frontendType);
297 eDVBRegisteredFrontend *new_fe = new eDVBRegisteredFrontend(frontend, adapter);
298 // CONNECT(new_fe->stateChanged, eDVBResourceManager::feStateChanged);
299 m_simulate_frontend.push_back(new_fe);
300 frontend->setSEC(m_sec);
301 // we must link all dvb-t frontends ( for active antenna voltage )
302 if (frontendType == iDVBFrontend::feTerrestrial)
304 if (prev_dvbt_frontend)
306 prev_dvbt_frontend->m_frontend->setData(eDVBFrontend::LINKED_NEXT_PTR, (long)new_fe);
307 frontend->setData(eDVBFrontend::LINKED_PREV_PTR, (long)&(*prev_dvbt_frontend));
309 prev_dvbt_frontend = new_fe;
316 PyObject *eDVBResourceManager::setFrontendSlotInformations(ePyObject list)
318 if (!PyList_Check(list))
320 PyErr_SetString(PyExc_StandardError, "eDVBResourceManager::setFrontendSlotInformations argument should be a python list");
323 if ((unsigned int)PyList_Size(list) != m_frontend.size())
326 sprintf(blasel, "eDVBResourceManager::setFrontendSlotInformations list size incorrect %d frontends avail, but %d entries in slotlist",
327 m_frontend.size(), PyList_Size(list));
328 PyErr_SetString(PyExc_StandardError, blasel);
332 for (eSmartPtrList<eDVBRegisteredFrontend>::iterator i(m_frontend.begin()); i != m_frontend.end(); ++i)
334 ePyObject obj = PyList_GET_ITEM(list, pos++);
335 if (!i->m_frontend->setSlotInfo(obj))
339 for (eSmartPtrList<eDVBRegisteredFrontend>::iterator i(m_simulate_frontend.begin()); i != m_simulate_frontend.end(); ++i)
341 ePyObject obj = PyList_GET_ITEM(list, pos++);
342 if (!i->m_frontend->setSlotInfo(obj))
348 RESULT eDVBResourceManager::allocateFrontend(ePtr<eDVBAllocatedFrontend> &fe, ePtr<iDVBFrontendParameters> &feparm, bool simulate)
350 eSmartPtrList<eDVBRegisteredFrontend> &frontends = simulate ? m_simulate_frontend : m_frontend;
351 ePtr<eDVBRegisteredFrontend> best;
355 for (eSmartPtrList<eDVBRegisteredFrontend>::iterator i(frontends.begin()); i != frontends.end(); ++i)
357 int c = i->m_frontend->isCompatibleWith(feparm);
359 if (c) /* if we have at least one frontend which is compatible with the source, flag this. */
364 // eDebug("Slot %d, score %d", i->m_frontend->getSlotID(), c);
372 // eDebug("Slot %d, score %d... but BUSY!!!!!!!!!!!", i->m_frontend->getSlotID(), c);
377 fe = new eDVBAllocatedFrontend(best);
384 return errAllSourcesBusy;
386 return errNoSourceFound;
389 RESULT eDVBResourceManager::allocateFrontendByIndex(ePtr<eDVBAllocatedFrontend> &fe, int slot_index)
391 int err = errNoSourceFound;
392 for (eSmartPtrList<eDVBRegisteredFrontend>::iterator i(m_frontend.begin()); i != m_frontend.end(); ++i)
393 if (!i->m_inuse && i->m_frontend->getSlotID() == slot_index)
395 // check if another slot linked to this is in use
397 i->m_frontend->getData(eDVBFrontend::SATPOS_DEPENDS_PTR, tmp);
400 eDVBRegisteredFrontend *satpos_depends_to_fe = (eDVBRegisteredFrontend *)tmp;
401 if (satpos_depends_to_fe->m_inuse)
403 eDebug("another satpos depending frontend is in use.. so allocateFrontendByIndex not possible!");
404 err = errAllSourcesBusy;
405 goto alloc_fe_by_id_not_possible;
408 else // check linked tuners
410 i->m_frontend->getData(eDVBFrontend::LINKED_NEXT_PTR, tmp);
413 eDVBRegisteredFrontend *next = (eDVBRegisteredFrontend *) tmp;
416 eDebug("another linked frontend is in use.. so allocateFrontendByIndex not possible!");
417 err = errAllSourcesBusy;
418 goto alloc_fe_by_id_not_possible;
420 next->m_frontend->getData(eDVBFrontend::LINKED_NEXT_PTR, tmp);
422 i->m_frontend->getData(eDVBFrontend::LINKED_PREV_PTR, tmp);
425 eDVBRegisteredFrontend *prev = (eDVBRegisteredFrontend *) tmp;
428 eDebug("another linked frontend is in use.. so allocateFrontendByIndex not possible!");
429 err = errAllSourcesBusy;
430 goto alloc_fe_by_id_not_possible;
432 prev->m_frontend->getData(eDVBFrontend::LINKED_PREV_PTR, tmp);
435 fe = new eDVBAllocatedFrontend(i);
438 alloc_fe_by_id_not_possible:
443 #define capHoldDecodeReference 64
445 RESULT eDVBResourceManager::allocateDemux(eDVBRegisteredFrontend *fe, ePtr<eDVBAllocatedDemux> &demux, int &cap)
447 /* find first unused demux which is on same adapter as frontend (or any, if PVR)
448 never use the first one unless we need a decoding demux. */
450 eDebug("allocate demux");
451 eSmartPtrList<eDVBRegisteredDemux>::iterator i(m_demux.begin());
455 if (i == m_demux.end())
458 ePtr<eDVBRegisteredDemux> unused;
460 if (m_boxtype == DM800 || m_boxtype == DM500HD || m_boxtype == DM800SE) // dm800 / 500hd
462 cap |= capHoldDecodeReference; // this is checked in eDVBChannel::getDemux
463 for (; i != m_demux.end(); ++i, ++n)
474 if (i->m_adapter == fe->m_adapter &&
475 i->m_demux->getSource() == fe->m_frontend->getDVBID())
477 demux = new eDVBAllocatedDemux(i);
481 else if (i->m_demux->getSource() == -1) // PVR
483 demux = new eDVBAllocatedDemux(i);
489 else if (m_boxtype == DM7025) // ATI
491 /* FIXME: hardware demux policy */
492 if (!(cap & iDVBChannel::capDecode))
494 if (m_demux.size() > 2) /* assumed to be true, otherwise we have lost anyway */
501 for (; i != m_demux.end(); ++i, ++n)
503 int is_decode = n < 2;
505 int in_use = is_decode ? (i->m_demux->getRefCount() != 2) : i->m_inuse;
507 if ((!in_use) && ((!fe) || (i->m_adapter == fe->m_adapter)))
509 if ((cap & iDVBChannel::capDecode) && !is_decode)
516 else if (m_boxtype == DM8000)
518 cap |= capHoldDecodeReference; // this is checked in eDVBChannel::getDemux
519 for (; i != m_demux.end(); ++i, ++n)
528 else if (i->m_adapter == fe->m_adapter &&
529 i->m_demux->getSource() == fe->m_frontend->getDVBID())
531 demux = new eDVBAllocatedDemux(i);
535 else if (n == 4) // always use demux4 for PVR (demux 4 can not descramble...)
538 demux = new eDVBAllocatedDemux(i);
548 demux = new eDVBAllocatedDemux(unused);
550 demux->get().setSourceFrontend(fe->m_frontend->getDVBID());
552 demux->get().setSourcePVR(0);
556 eDebug("demux not found");
560 RESULT eDVBResourceManager::setChannelList(iDVBChannelList *list)
566 RESULT eDVBResourceManager::getChannelList(ePtr<iDVBChannelList> &list)
575 #define eDebugNoSimulate(x...) \
582 // eDebugNoNewLine("SIMULATE:"); \
587 RESULT eDVBResourceManager::allocateChannel(const eDVBChannelID &channelid, eUsePtr<iDVBChannel> &channel, bool simulate)
589 /* first, check if a channel is already existing. */
590 std::list<active_channel> &active_channels = simulate ? m_active_simulate_channels : m_active_channels;
592 if (!simulate && m_cached_channel)
594 eDVBChannel *cache_chan = (eDVBChannel*)&(*m_cached_channel);
595 if(channelid==cache_chan->getChannelID())
597 eDebug("use cached_channel");
598 channel = m_cached_channel;
601 m_cached_channel_state_changed_conn.disconnect();
603 m_releaseCachedChannelTimer->stop();
606 eDebugNoSimulate("allocate channel.. %04x:%04x", channelid.transport_stream_id.get(), channelid.original_network_id.get());
607 for (std::list<active_channel>::iterator i(active_channels.begin()); i != active_channels.end(); ++i)
609 eDebugNoSimulate("available channel.. %04x:%04x", i->m_channel_id.transport_stream_id.get(), i->m_channel_id.original_network_id.get());
610 if (i->m_channel_id == channelid)
612 eDebugNoSimulate("found shared channel..");
613 channel = i->m_channel;
618 /* no currently available channel is tuned to this channelid. create a new one, if possible. */
622 eDebugNoSimulate("no channel list set!");
623 return errNoChannelList;
626 ePtr<iDVBFrontendParameters> feparm;
627 if (m_list->getChannelFrontendData(channelid, feparm))
629 eDebugNoSimulate("channel not found!");
630 return errChannelNotInList;
633 /* allocate a frontend. */
635 ePtr<eDVBAllocatedFrontend> fe;
637 int err = allocateFrontend(fe, feparm, simulate);
642 ePtr<eDVBChannel> ch = new eDVBChannel(this, fe);
644 res = ch->setChannel(channelid, feparm);
648 return errChidNotFound;
655 m_cached_channel = channel = ch;
656 m_cached_channel_state_changed_conn =
657 CONNECT(ch->m_stateChanged,eDVBResourceManager::DVBChannelStateChanged);
663 void eDVBResourceManager::DVBChannelStateChanged(iDVBChannel *chan)
666 chan->getState(state);
669 case iDVBChannel::state_release:
670 case iDVBChannel::state_ok:
672 eDebug("stop release channel timer");
673 m_releaseCachedChannelTimer->stop();
676 case iDVBChannel::state_last_instance:
678 eDebug("start release channel timer");
679 m_releaseCachedChannelTimer->start(3000, true);
682 default: // ignore all other events
687 void eDVBResourceManager::releaseCachedChannel()
689 eDebug("release cached channel (timer timeout)");
693 RESULT eDVBResourceManager::allocateRawChannel(eUsePtr<iDVBChannel> &channel, int slot_index)
695 ePtr<eDVBAllocatedFrontend> fe;
697 if (m_cached_channel)
699 m_cached_channel_state_changed_conn.disconnect();
701 m_releaseCachedChannelTimer->stop();
704 int err = allocateFrontendByIndex(fe, slot_index);
708 channel = new eDVBChannel(this, fe);
713 RESULT eDVBResourceManager::allocatePVRChannel(eUsePtr<iDVBPVRChannel> &channel)
715 ePtr<eDVBAllocatedDemux> demux;
717 if (m_cached_channel && m_releaseCachedChannelTimer->isActive())
719 m_cached_channel_state_changed_conn.disconnect();
721 m_releaseCachedChannelTimer->stop();
724 channel = new eDVBChannel(this, 0);
728 RESULT eDVBResourceManager::addChannel(const eDVBChannelID &chid, eDVBChannel *ch)
730 ePtr<iDVBFrontend> fe;
731 if (!ch->getFrontend(fe))
733 eDVBFrontend *frontend = (eDVBFrontend*)&(*fe);
734 if (frontend->is_simulate())
735 m_active_simulate_channels.push_back(active_channel(chid, ch));
738 m_active_channels.push_back(active_channel(chid, ch));
739 /* emit */ m_channelAdded(ch);
745 RESULT eDVBResourceManager::removeChannel(eDVBChannel *ch)
747 ePtr<iDVBFrontend> fe;
748 if (!ch->getFrontend(fe))
750 eDVBFrontend *frontend = (eDVBFrontend*)&(*fe);
751 std::list<active_channel> &active_channels = frontend->is_simulate() ? m_active_simulate_channels : m_active_channels;
753 for (std::list<active_channel>::iterator i(active_channels.begin()); i != active_channels.end();)
755 if (i->m_channel == ch)
757 i = active_channels.erase(i);
769 RESULT eDVBResourceManager::connectChannelAdded(const Slot1<void,eDVBChannel*> &channelAdded, ePtr<eConnection> &connection)
771 connection = new eConnection((eDVBResourceManager*)this, m_channelAdded.connect(channelAdded));
775 int eDVBResourceManager::canAllocateFrontend(ePtr<iDVBFrontendParameters> &feparm, bool simulate)
777 eSmartPtrList<eDVBRegisteredFrontend> &frontends = simulate ? m_simulate_frontend : m_frontend;
778 ePtr<eDVBRegisteredFrontend> best;
781 for (eSmartPtrList<eDVBRegisteredFrontend>::iterator i(frontends.begin()); i != frontends.end(); ++i)
784 int c = i->m_frontend->isCompatibleWith(feparm);
791 int tuner_type_channel_default(ePtr<iDVBChannelList> &channellist, const eDVBChannelID &chid)
795 ePtr<iDVBFrontendParameters> feparm;
796 if (!channellist->getChannelFrontendData(chid, feparm))
799 if (!feparm->getSystem(system))
803 case iDVBFrontend::feSatellite:
805 case iDVBFrontend::feCable:
807 case iDVBFrontend::feTerrestrial:
818 int eDVBResourceManager::canAllocateChannel(const eDVBChannelID &channelid, const eDVBChannelID& ignore, bool simulate)
820 std::list<active_channel> &active_channels = simulate ? m_active_simulate_channels : m_active_channels;
822 if (!simulate && m_cached_channel)
824 eDVBChannel *cache_chan = (eDVBChannel*)&(*m_cached_channel);
825 if(channelid==cache_chan->getChannelID())
826 return tuner_type_channel_default(m_list, channelid);
829 /* first, check if a channel is already existing. */
830 // eDebug("allocate channel.. %04x:%04x", channelid.transport_stream_id.get(), channelid.original_network_id.get());
831 for (std::list<active_channel>::iterator i(active_channels.begin()); i != active_channels.end(); ++i)
833 // eDebug("available channel.. %04x:%04x", i->m_channel_id.transport_stream_id.get(), i->m_channel_id.original_network_id.get());
834 if (i->m_channel_id == channelid)
836 // eDebug("found shared channel..");
837 return tuner_type_channel_default(m_list, channelid);
841 int *decremented_cached_channel_fe_usecount=NULL,
842 *decremented_fe_usecount=NULL;
844 for (std::list<active_channel>::iterator i(active_channels.begin()); i != active_channels.end(); ++i)
846 eSmartPtrList<eDVBRegisteredFrontend> &frontends = simulate ? m_simulate_frontend : m_frontend;
847 // eDebug("available channel.. %04x:%04x", i->m_channel_id.transport_stream_id.get(), i->m_channel_id.original_network_id.get());
848 if (i->m_channel_id == ignore)
850 eDVBChannel *channel = (eDVBChannel*) &(*i->m_channel);
851 // one eUsePtr<iDVBChannel> is used in eDVBServicePMTHandler
852 // another on eUsePtr<iDVBChannel> is used in the eDVBScan instance used in eDVBServicePMTHandler (for SDT scan)
853 // so we must check here if usecount is 3 (when the channel is equal to the cached channel)
854 // or 2 when the cached channel is not equal to the compared channel
855 if (channel == &(*m_cached_channel) ? channel->getUseCount() == 3 : channel->getUseCount() == 2) // channel only used once..
857 ePtr<iDVBFrontend> fe;
858 if (!i->m_channel->getFrontend(fe))
860 for (eSmartPtrList<eDVBRegisteredFrontend>::iterator ii(frontends.begin()); ii != frontends.end(); ++ii)
862 if ( &(*fe) == &(*ii->m_frontend) )
865 decremented_fe_usecount = &ii->m_inuse;
866 if (channel == &(*m_cached_channel))
867 decremented_cached_channel_fe_usecount = decremented_fe_usecount;
877 if (!decremented_cached_channel_fe_usecount)
879 if (m_cached_channel)
881 eDVBChannel *channel = (eDVBChannel*) &(*m_cached_channel);
882 if (channel->getUseCount() == 1)
884 ePtr<iDVBFrontend> fe;
885 if (!channel->getFrontend(fe))
887 eSmartPtrList<eDVBRegisteredFrontend> &frontends = simulate ? m_simulate_frontend : m_frontend;
888 for (eSmartPtrList<eDVBRegisteredFrontend>::iterator ii(frontends.begin()); ii != frontends.end(); ++ii)
890 if ( &(*fe) == &(*ii->m_frontend) )
893 decremented_cached_channel_fe_usecount = &ii->m_inuse;
902 decremented_cached_channel_fe_usecount=NULL;
904 ePtr<iDVBFrontendParameters> feparm;
908 eDebug("no channel list set!");
912 if (m_list->getChannelFrontendData(channelid, feparm))
914 eDebug("channel not found!");
918 ret = canAllocateFrontend(feparm, simulate);
921 if (decremented_fe_usecount)
922 ++(*decremented_fe_usecount);
923 if (decremented_cached_channel_fe_usecount)
924 ++(*decremented_cached_channel_fe_usecount);
929 bool eDVBResourceManager::canMeasureFrontendInputPower()
931 for (eSmartPtrList<eDVBRegisteredFrontend>::iterator i(m_frontend.begin()); i != m_frontend.end(); ++i)
933 return i->m_frontend->readInputpower() >= 0;
938 class eDVBChannelFilePush: public eFilePushThread
941 eDVBChannelFilePush() { setIFrameSearch(0); setTimebaseChange(0); }
942 void setIFrameSearch(int enabled) { m_iframe_search = enabled; m_iframe_state = 0; }
944 /* "timebase change" is for doing trickmode playback at an exact speed, even when pictures are skipped. */
945 /* you need to set it to 1/16 if you want 16x playback, for example. you need video master sync. */
946 void setTimebaseChange(int ratio) { m_timebase_change = ratio; } /* 16bit fixpoint, 0 for disable */
948 int m_iframe_search, m_iframe_state, m_pid;
949 int m_timebase_change;
950 int filterRecordData(const unsigned char *data, int len, size_t ¤t_span_remaining);
953 int eDVBChannelFilePush::filterRecordData(const unsigned char *_data, int len, size_t ¤t_span_remaining)
956 if (m_timebase_change)
958 eDebug("timebase change: %d", m_timebase_change);
960 for (offset = 0; offset < len; offset += 188)
962 unsigned char *pkt = (unsigned char*)_data + offset;
963 if (pkt[1] & 0x40) /* pusi */
965 if (pkt[3] & 0x20) // adaption field present?
966 pkt += pkt[4] + 4 + 1; /* skip adaption field and header */
968 pkt += 4; /* skip header */
969 if (pkt[0] || pkt[1] || (pkt[2] != 1))
971 eWarning("broken startcode");
977 if (pkt[7] & 0x80) // PTS present?
979 pts = ((unsigned long long)(pkt[ 9]&0xE)) << 29;
980 pts |= ((unsigned long long)(pkt[10]&0xFF)) << 22;
981 pts |= ((unsigned long long)(pkt[11]&0xFE)) << 14;
982 pts |= ((unsigned long long)(pkt[12]&0xFF)) << 7;
983 pts |= ((unsigned long long)(pkt[13]&0xFE)) >> 1;
987 RESULT r = m_tstools.fixupPTS(off, pts);
989 eWarning("fixup PTS while trickmode playback failed.\n");
992 int sec = pts / 90000;
993 int frm = pts % 90000;
1001 // eDebug("original, fixed pts: %016llx %d:%02d:%02d:%02d:%05d", pts, d, hr, min, sec, frm);
1003 pts += 0x80000000LL;
1004 pts *= m_timebase_change;
1016 // eDebug("new pts (after timebase change): %016llx %d:%02d:%02d:%02d:%05d", pts, d, hr, min, sec, frm);
1024 pkt[9] |= (pts >> 29) & 0xE;
1025 pkt[10] |= (pts >> 22) & 0xFF;
1026 pkt[11] |= (pts >> 14) & 0xFE;
1027 pkt[12] |= (pts >> 7) & 0xFF;
1028 pkt[13] |= (pts << 1) & 0xFE;
1036 if (!m_iframe_search)
1039 unsigned char *data = (unsigned char*)_data; /* remove that const. we know what we are doing. */
1041 // eDebug("filterRecordData, size=%d (mod 188=%d), first byte is %02x", len, len %188, data[0]);
1043 unsigned char *d = data;
1044 while ((d + 3 < data + len) && (d = (unsigned char*)memmem(d, data + len - d, "\x00\x00\x01", 3)))
1046 int offset = d - data;
1047 int ts_offset = offset - offset % 188; /* offset to the start of TS packet */
1048 unsigned char *ts = data + ts_offset;
1049 int pid = ((ts[1] << 8) | ts[2]) & 0x1FFF;
1051 if ((d[3] == 0 || d[3] == 0x09 && d[-1] == 0 && (ts[1] & 0x40)) && (m_pid == pid)) /* picture start */
1053 int picture_type = (d[3]==0 ? (d[5] >> 3) & 7 : (d[4] >> 5) + 1);
1056 // eDebug("%d-frame at %d, offset in TS packet: %d, pid=%04x", picture_type, offset, offset % 188, pid);
1058 if (m_iframe_state == 1)
1060 /* we are allowing data, and stop allowing data on the next frame.
1061 we now found a frame. so stop here. */
1062 memset(data + offset, 0, 188 - (offset%188)); /* zero out rest of TS packet */
1063 current_span_remaining = 0;
1065 unsigned char *fts = ts + 188;
1066 while (fts < (data + len))
1069 fts[2] |= 0xff; /* drop packet */
1073 return len; // ts_offset + 188; /* deliver this packet, but not more. */
1076 if (picture_type != 1) /* we are only interested in I frames */
1079 unsigned char *fts = data;
1083 fts[2] |= 0xff; /* drop packet */
1090 } else if ((d[3] & 0xF0) == 0xE0) /* video stream */
1092 /* verify that this is actually a PES header, not just some ES data */
1093 if (ts[1] & 0x40) /* PUSI set */
1095 int payload_start = 4;
1096 if (ts[3] & 0x20) /* adaptation field present */
1097 payload_start += ts[4] + 1; /* skip AF */
1098 if (payload_start == (offset%188)) /* the 00 00 01 should be directly at the payload start, otherwise it's not a PES header */
1102 eDebug("now locked to pid %04x (%02x %02x %02x %02x)", pid, ts[0], ts[1], ts[2], ts[3]);
1110 d += 4; /* ignore */
1113 if (m_iframe_state == 1)
1116 return 0; /* we need find an iframe first */
1122 DEFINE_REF(eDVBChannel);
1124 eDVBChannel::eDVBChannel(eDVBResourceManager *mgr, eDVBAllocatedFrontend *frontend): m_state(state_idle), m_mgr(mgr)
1126 m_frontend = frontend;
1131 m_skipmode_n = m_skipmode_m = m_skipmode_frames = 0;
1134 m_frontend->get().connectStateChange(slot(*this, &eDVBChannel::frontendStateChanged), m_conn_frontendStateChanged);
1137 eDVBChannel::~eDVBChannel()
1140 m_mgr->removeChannel(this);
1145 void eDVBChannel::frontendStateChanged(iDVBFrontend*fe)
1147 int state, ourstate = 0;
1149 /* if we are already in shutdown, don't change state. */
1150 if (m_state == state_release)
1153 if (fe->getState(state))
1156 if (state == iDVBFrontend::stateLock)
1158 eDebug("OURSTATE: ok");
1159 ourstate = state_ok;
1160 } else if (state == iDVBFrontend::stateTuning)
1162 eDebug("OURSTATE: tuning");
1163 ourstate = state_tuning;
1164 } else if (state == iDVBFrontend::stateLostLock)
1166 /* on managed channels, we try to retune in order to re-acquire lock. */
1167 if (m_current_frontend_parameters)
1169 eDebug("OURSTATE: lost lock, trying to retune");
1170 ourstate = state_tuning;
1171 m_frontend->get().tune(*m_current_frontend_parameters);
1173 /* on unmanaged channels, we don't do this. the client will do this. */
1175 eDebug("OURSTATE: lost lock, unavailable now.");
1176 ourstate = state_unavailable;
1178 } else if (state == iDVBFrontend::stateFailed)
1180 eDebug("OURSTATE: failed");
1181 ourstate = state_failed;
1183 eFatal("state unknown");
1185 if (ourstate != m_state)
1188 m_stateChanged(this);
1192 void eDVBChannel::pvrEvent(int event)
1196 case eFilePushThread::evtEOF:
1197 eDebug("eDVBChannel: End of file!");
1198 m_event(this, evtEOF);
1200 case eFilePushThread::evtUser: /* start */
1202 m_event(this, evtSOF);
1207 void eDVBChannel::cueSheetEvent(int event)
1209 /* we might end up here if playing failed or stopped, but the client hasn't (yet) noted. */
1214 case eCueSheet::evtSeek:
1216 flushPVR(m_cue->m_decoding_demux);
1218 case eCueSheet::evtSkipmode:
1221 m_cue->m_lock.WrLock();
1222 m_cue->m_seek_requests.push_back(std::pair<int, pts_t>(1, 0)); /* resync */
1223 m_cue->m_lock.Unlock();
1224 eRdLocker l(m_cue->m_lock);
1225 if (m_cue->m_skipmode_ratio)
1227 int bitrate = m_tstools.calcBitrate(); /* in bits/s */
1228 eDebug("skipmode ratio is %lld:90000, bitrate is %d bit/s", m_cue->m_skipmode_ratio, bitrate);
1229 /* i agree that this might look a bit like black magic. */
1230 m_skipmode_n = 512*1024; /* must be 1 iframe at least. */
1231 m_skipmode_m = bitrate / 8 / 90000 * m_cue->m_skipmode_ratio / 8;
1232 m_skipmode_frames = m_cue->m_skipmode_ratio / 90000;
1233 m_skipmode_frames_remainder = 0;
1235 if (m_cue->m_skipmode_ratio < 0)
1236 m_skipmode_m -= m_skipmode_n;
1238 eDebug("resolved to: %d %d", m_skipmode_m, m_skipmode_n);
1240 if (abs(m_skipmode_m) < abs(m_skipmode_n))
1242 eWarning("something is wrong with this calculation");
1243 m_skipmode_frames = m_skipmode_n = m_skipmode_m = 0;
1247 eDebug("skipmode ratio is 0, normal play");
1248 m_skipmode_frames = m_skipmode_n = m_skipmode_m = 0;
1251 m_pvr_thread->setIFrameSearch(m_skipmode_n != 0);
1252 if (m_cue->m_skipmode_ratio != 0)
1253 m_pvr_thread->setTimebaseChange(0x10000 * 9000 / (m_cue->m_skipmode_ratio / 10)); /* negative values are also ok */
1255 m_pvr_thread->setTimebaseChange(0); /* normal playback */
1256 eDebug("flush pvr");
1257 flushPVR(m_cue->m_decoding_demux);
1261 case eCueSheet::evtSpanChanged:
1263 m_source_span.clear();
1264 for (std::list<std::pair<pts_t, pts_t> >::const_iterator i(m_cue->m_spans.begin()); i != m_cue->m_spans.end(); ++i)
1266 off_t offset_in, offset_out;
1267 pts_t pts_in = i->first, pts_out = i->second;
1268 if (m_tstools.getOffset(offset_in, pts_in, -1) || m_tstools.getOffset(offset_out, pts_out, 1))
1270 eDebug("span translation failed.\n");
1273 eDebug("source span: %llx .. %llx, translated to %llx..%llx", pts_in, pts_out, offset_in, offset_out);
1274 m_source_span.push_back(std::pair<off_t, off_t>(offset_in, offset_out));
1281 /* align toward zero */
1282 static inline long long align(long long x, int align)
1297 /* align toward zero */
1298 static inline long long align_with_len(long long x, int align, size_t &len)
1314 /* remember, this gets called from another thread. */
1315 void eDVBChannel::getNextSourceSpan(off_t current_offset, size_t bytes_read, off_t &start, size_t &size)
1317 const int blocksize = 188;
1318 unsigned int max = align(10*1024*1024, blocksize);
1319 current_offset = align(current_offset, blocksize);
1323 eDebug("no cue sheet. forcing normal play");
1324 start = current_offset;
1331 eDebug("skipmode %d:%d (x%d)", m_skipmode_m, m_skipmode_n, m_skipmode_frames);
1332 max = align(m_skipmode_n, blocksize);
1335 eDebug("getNextSourceSpan, current offset is %08llx, m_skipmode_m = %d!", current_offset, m_skipmode_m);
1336 int frame_skip_success = 0;
1340 int frames_to_skip = m_skipmode_frames + m_skipmode_frames_remainder;
1341 eDebug("we are at %llx, and we try to skip %d+%d frames from here", current_offset, m_skipmode_frames, m_skipmode_frames_remainder);
1343 off_t iframe_start = current_offset;
1344 int frames_skipped = frames_to_skip;
1345 if (!m_tstools.findNextPicture(iframe_start, iframe_len, frames_skipped))
1347 m_skipmode_frames_remainder = frames_to_skip - frames_skipped;
1348 eDebug("successfully skipped %d (out of %d, rem now %d) frames.", frames_skipped, frames_to_skip, m_skipmode_frames_remainder);
1349 current_offset = align_with_len(iframe_start, blocksize, iframe_len);
1350 max = align(iframe_len + 187, blocksize);
1351 frame_skip_success = 1;
1354 m_skipmode_frames_remainder = 0;
1355 eDebug("frame skipping failed, reverting to byte-skipping");
1359 if (!frame_skip_success)
1361 current_offset += align(m_skipmode_m, blocksize);
1365 eDebug("we are at %llx, and we try to find the iframe here:", current_offset);
1367 off_t iframe_start = current_offset;
1369 int direction = (m_skipmode_m < 0) ? -1 : +1;
1370 if (m_tstools.findFrame(iframe_start, iframe_len, direction))
1374 current_offset = align_with_len(iframe_start, blocksize, iframe_len);
1375 max = align(iframe_len, blocksize);
1380 m_cue->m_lock.RdLock();
1382 while (!m_cue->m_seek_requests.empty())
1384 std::pair<int, pts_t> seek = m_cue->m_seek_requests.front();
1385 m_cue->m_lock.Unlock();
1386 m_cue->m_lock.WrLock();
1387 m_cue->m_seek_requests.pop_front();
1388 m_cue->m_lock.Unlock();
1389 m_cue->m_lock.RdLock();
1390 int relative = seek.first;
1391 pts_t pts = seek.second;
1396 if (!m_cue->m_decoder)
1398 eDebug("no decoder - can't seek relative");
1401 if (m_cue->m_decoder->getPTS(0, now))
1403 eDebug("decoder getPTS failed, can't seek relative");
1406 if (!m_cue->m_decoding_demux)
1408 eDebug("getNextSourceSpan, no decoding demux. couldn't seek to %llx... ignore request!", pts);
1409 start = current_offset;
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);
1465 eDebug("ok, resolved skip (rel: %d, diff %lld), now at %08llx", relative, pts, offset);
1466 current_offset = align(offset, blocksize); /* in case tstools return non-aligned offset */
1469 m_cue->m_lock.Unlock();
1471 for (std::list<std::pair<off_t, off_t> >::const_iterator i(m_source_span.begin()); i != m_source_span.end(); ++i)
1473 long long aligned_start = align(i->first, blocksize);
1474 long long aligned_end = align(i->second, blocksize);
1476 if ((current_offset >= aligned_start) && (current_offset < aligned_end))
1478 start = current_offset;
1479 /* max can not exceed max(size_t). aligned_end - current_offset, however, can. */
1480 if ((aligned_end - current_offset) > max)
1483 size = aligned_end - current_offset;
1484 eDebug("HIT, %lld < %lld < %lld, size: %d", i->first, current_offset, i->second, size);
1487 if (current_offset < aligned_start)
1489 /* ok, our current offset is in an 'out' zone. */
1490 if ((m_skipmode_m >= 0) || (i == m_source_span.begin()))
1492 /* in normal playback, just start at the next zone. */
1495 /* size is not 64bit! */
1496 if ((i->second - i->first) > max)
1499 size = aligned_end - aligned_start;
1502 if (m_skipmode_m < 0)
1504 eDebug("reached SOF");
1507 m_pvr_thread->sendEvent(eFilePushThread::evtUser);
1511 /* when skipping reverse, however, choose the zone before. */
1513 eDebug("skip to previous block, which is %llx..%llx", i->first, i->second);
1516 aligned_start = align(i->first, blocksize);
1517 aligned_end = align(i->second, blocksize);
1519 if ((aligned_end - aligned_start) > max)
1522 len = aligned_end - aligned_start;
1524 start = aligned_end - len;
1525 eDebug("skipping to %llx, %d", start, len);
1528 eDebug("result: %llx, %x (%llx %llx)", start, size, aligned_start, aligned_end);
1533 if ((current_offset < -m_skipmode_m) && (m_skipmode_m < 0))
1535 eDebug("reached SOF");
1537 m_pvr_thread->sendEvent(eFilePushThread::evtUser);
1540 if (m_source_span.empty())
1542 start = current_offset;
1544 eDebug("NO CUESHEET. (%08llx, %d)", start, size);
1547 start = current_offset;
1553 void eDVBChannel::AddUse()
1555 if (++m_use_count > 1 && m_state == state_last_instance)
1558 m_stateChanged(this);
1562 void eDVBChannel::ReleaseUse()
1566 m_state = state_release;
1567 m_stateChanged(this);
1569 else if (m_use_count == 1)
1571 m_state = state_last_instance;
1572 m_stateChanged(this);
1576 RESULT eDVBChannel::setChannel(const eDVBChannelID &channelid, ePtr<iDVBFrontendParameters> &feparm)
1579 m_mgr->removeChannel(this);
1586 eDebug("no frontend to tune!");
1590 m_channel_id = channelid;
1591 m_mgr->addChannel(channelid, this);
1592 m_state = state_tuning;
1593 /* if tuning fails, shutdown the channel immediately. */
1595 res = m_frontend->get().tune(*feparm);
1596 m_current_frontend_parameters = feparm;
1600 m_state = state_release;
1601 m_stateChanged(this);
1608 RESULT eDVBChannel::connectStateChange(const Slot1<void,iDVBChannel*> &stateChange, ePtr<eConnection> &connection)
1610 connection = new eConnection((iDVBChannel*)this, m_stateChanged.connect(stateChange));
1614 RESULT eDVBChannel::connectEvent(const Slot2<void,iDVBChannel*,int> &event, ePtr<eConnection> &connection)
1616 connection = new eConnection((iDVBChannel*)this, m_event.connect(event));
1620 RESULT eDVBChannel::getState(int &state)
1626 RESULT eDVBChannel::setCIRouting(const eDVBCIRouting &routing)
1631 void eDVBChannel::SDTready(int result)
1633 ePyObject args = PyTuple_New(2), ret;
1637 for (std::vector<ServiceDescriptionSection*>::const_iterator i = m_SDT->getSections().begin(); i != m_SDT->getSections().end(); ++i)
1640 PyTuple_SET_ITEM(args, 0, PyInt_FromLong((*i)->getTransportStreamId()));
1641 PyTuple_SET_ITEM(args, 1, PyInt_FromLong((*i)->getOriginalNetworkId()));
1647 PyTuple_SET_ITEM(args, 0, Py_None);
1648 PyTuple_SET_ITEM(args, 1, Py_None);
1652 ret = PyObject_CallObject(m_tsid_onid_callback, args);
1656 Py_DECREF(m_tsid_onid_callback);
1657 m_tsid_onid_callback = ePyObject();
1658 m_tsid_onid_demux = 0;
1662 int eDVBChannel::reserveDemux()
1664 ePtr<iDVBDemux> dmx;
1665 if (!getDemux(dmx, 0))
1668 if (!dmx->getCADemuxID(id))
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));