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 unsigned int assigned=0;
324 for (eSmartPtrList<eDVBRegisteredFrontend>::iterator i(m_frontend.begin()); i != m_frontend.end(); ++i)
327 while (pos < PyList_Size(list)) {
328 ePyObject obj = PyList_GET_ITEM(list, pos++);
329 if (!i->m_frontend->setSlotInfo(obj))
335 if (assigned != m_frontend.size()) {
337 sprintf(blasel, "eDVBResourceManager::setFrontendSlotInformations .. assigned %d socket informations, but %d registered frontends!",
338 m_frontend.size(), assigned);
339 PyErr_SetString(PyExc_StandardError, blasel);
342 for (eSmartPtrList<eDVBRegisteredFrontend>::iterator i(m_simulate_frontend.begin()); i != m_simulate_frontend.end(); ++i)
345 while (pos < PyList_Size(list)) {
346 ePyObject obj = PyList_GET_ITEM(list, pos++);
347 if (!i->m_frontend->setSlotInfo(obj))
355 RESULT eDVBResourceManager::allocateFrontend(ePtr<eDVBAllocatedFrontend> &fe, ePtr<iDVBFrontendParameters> &feparm, bool simulate)
357 eSmartPtrList<eDVBRegisteredFrontend> &frontends = simulate ? m_simulate_frontend : m_frontend;
358 ePtr<eDVBRegisteredFrontend> best;
362 for (eSmartPtrList<eDVBRegisteredFrontend>::iterator i(frontends.begin()); i != frontends.end(); ++i)
364 int c = i->m_frontend->isCompatibleWith(feparm);
366 if (c) /* if we have at least one frontend which is compatible with the source, flag this. */
371 // eDebug("Slot %d, score %d", i->m_frontend->getSlotID(), c);
379 // eDebug("Slot %d, score %d... but BUSY!!!!!!!!!!!", i->m_frontend->getSlotID(), c);
384 fe = new eDVBAllocatedFrontend(best);
391 return errAllSourcesBusy;
393 return errNoSourceFound;
396 RESULT eDVBResourceManager::allocateFrontendByIndex(ePtr<eDVBAllocatedFrontend> &fe, int slot_index)
398 int err = errNoSourceFound;
399 for (eSmartPtrList<eDVBRegisteredFrontend>::iterator i(m_frontend.begin()); i != m_frontend.end(); ++i)
400 if (!i->m_inuse && i->m_frontend->getSlotID() == slot_index)
402 // check if another slot linked to this is in use
404 i->m_frontend->getData(eDVBFrontend::SATPOS_DEPENDS_PTR, tmp);
407 eDVBRegisteredFrontend *satpos_depends_to_fe = (eDVBRegisteredFrontend *)tmp;
408 if (satpos_depends_to_fe->m_inuse)
410 eDebug("another satpos depending frontend is in use.. so allocateFrontendByIndex not possible!");
411 err = errAllSourcesBusy;
412 goto alloc_fe_by_id_not_possible;
415 else // check linked tuners
417 i->m_frontend->getData(eDVBFrontend::LINKED_NEXT_PTR, tmp);
420 eDVBRegisteredFrontend *next = (eDVBRegisteredFrontend *) tmp;
423 eDebug("another linked frontend is in use.. so allocateFrontendByIndex not possible!");
424 err = errAllSourcesBusy;
425 goto alloc_fe_by_id_not_possible;
427 next->m_frontend->getData(eDVBFrontend::LINKED_NEXT_PTR, tmp);
429 i->m_frontend->getData(eDVBFrontend::LINKED_PREV_PTR, tmp);
432 eDVBRegisteredFrontend *prev = (eDVBRegisteredFrontend *) tmp;
435 eDebug("another linked frontend is in use.. so allocateFrontendByIndex not possible!");
436 err = errAllSourcesBusy;
437 goto alloc_fe_by_id_not_possible;
439 prev->m_frontend->getData(eDVBFrontend::LINKED_PREV_PTR, tmp);
442 fe = new eDVBAllocatedFrontend(i);
445 alloc_fe_by_id_not_possible:
450 #define capHoldDecodeReference 64
452 RESULT eDVBResourceManager::allocateDemux(eDVBRegisteredFrontend *fe, ePtr<eDVBAllocatedDemux> &demux, int &cap)
454 /* find first unused demux which is on same adapter as frontend (or any, if PVR)
455 never use the first one unless we need a decoding demux. */
457 eDebug("allocate demux");
458 eSmartPtrList<eDVBRegisteredDemux>::iterator i(m_demux.begin());
462 if (i == m_demux.end())
465 ePtr<eDVBRegisteredDemux> unused;
467 if (m_boxtype == DM800 || m_boxtype == DM500HD || m_boxtype == DM800SE) // dm800 / 500hd
469 cap |= capHoldDecodeReference; // this is checked in eDVBChannel::getDemux
470 for (; i != m_demux.end(); ++i, ++n)
481 if (i->m_adapter == fe->m_adapter &&
482 i->m_demux->getSource() == fe->m_frontend->getDVBID())
484 demux = new eDVBAllocatedDemux(i);
488 else if (i->m_demux->getSource() == -1) // PVR
490 demux = new eDVBAllocatedDemux(i);
496 else if (m_boxtype == DM7025) // ATI
498 /* FIXME: hardware demux policy */
499 if (!(cap & iDVBChannel::capDecode))
501 if (m_demux.size() > 2) /* assumed to be true, otherwise we have lost anyway */
508 for (; i != m_demux.end(); ++i, ++n)
510 int is_decode = n < 2;
512 int in_use = is_decode ? (i->m_demux->getRefCount() != 2) : i->m_inuse;
514 if ((!in_use) && ((!fe) || (i->m_adapter == fe->m_adapter)))
516 if ((cap & iDVBChannel::capDecode) && !is_decode)
523 else if (m_boxtype == DM8000)
525 cap |= capHoldDecodeReference; // this is checked in eDVBChannel::getDemux
526 for (; i != m_demux.end(); ++i, ++n)
535 else if (i->m_adapter == fe->m_adapter &&
536 i->m_demux->getSource() == fe->m_frontend->getDVBID())
538 demux = new eDVBAllocatedDemux(i);
542 else if (n == 4) // always use demux4 for PVR (demux 4 can not descramble...)
545 demux = new eDVBAllocatedDemux(i);
555 demux = new eDVBAllocatedDemux(unused);
557 demux->get().setSourceFrontend(fe->m_frontend->getDVBID());
559 demux->get().setSourcePVR(0);
563 eDebug("demux not found");
567 RESULT eDVBResourceManager::setChannelList(iDVBChannelList *list)
573 RESULT eDVBResourceManager::getChannelList(ePtr<iDVBChannelList> &list)
582 #define eDebugNoSimulate(x...) \
589 // eDebugNoNewLine("SIMULATE:"); \
594 RESULT eDVBResourceManager::allocateChannel(const eDVBChannelID &channelid, eUsePtr<iDVBChannel> &channel, bool simulate)
596 /* first, check if a channel is already existing. */
597 std::list<active_channel> &active_channels = simulate ? m_active_simulate_channels : m_active_channels;
599 if (!simulate && m_cached_channel)
601 eDVBChannel *cache_chan = (eDVBChannel*)&(*m_cached_channel);
602 if(channelid==cache_chan->getChannelID())
604 eDebug("use cached_channel");
605 channel = m_cached_channel;
608 m_cached_channel_state_changed_conn.disconnect();
610 m_releaseCachedChannelTimer->stop();
613 eDebugNoSimulate("allocate channel.. %04x:%04x", channelid.transport_stream_id.get(), channelid.original_network_id.get());
614 for (std::list<active_channel>::iterator i(active_channels.begin()); i != active_channels.end(); ++i)
616 eDebugNoSimulate("available channel.. %04x:%04x", i->m_channel_id.transport_stream_id.get(), i->m_channel_id.original_network_id.get());
617 if (i->m_channel_id == channelid)
619 eDebugNoSimulate("found shared channel..");
620 channel = i->m_channel;
625 /* no currently available channel is tuned to this channelid. create a new one, if possible. */
629 eDebugNoSimulate("no channel list set!");
630 return errNoChannelList;
633 ePtr<iDVBFrontendParameters> feparm;
634 if (m_list->getChannelFrontendData(channelid, feparm))
636 eDebugNoSimulate("channel not found!");
637 return errChannelNotInList;
640 /* allocate a frontend. */
642 ePtr<eDVBAllocatedFrontend> fe;
644 int err = allocateFrontend(fe, feparm, simulate);
649 ePtr<eDVBChannel> ch = new eDVBChannel(this, fe);
651 res = ch->setChannel(channelid, feparm);
655 return errChidNotFound;
662 m_cached_channel = channel = ch;
663 m_cached_channel_state_changed_conn =
664 CONNECT(ch->m_stateChanged,eDVBResourceManager::DVBChannelStateChanged);
670 void eDVBResourceManager::DVBChannelStateChanged(iDVBChannel *chan)
673 chan->getState(state);
676 case iDVBChannel::state_release:
677 case iDVBChannel::state_ok:
679 eDebug("stop release channel timer");
680 m_releaseCachedChannelTimer->stop();
683 case iDVBChannel::state_last_instance:
685 eDebug("start release channel timer");
686 m_releaseCachedChannelTimer->start(3000, true);
689 default: // ignore all other events
694 void eDVBResourceManager::releaseCachedChannel()
696 eDebug("release cached channel (timer timeout)");
700 RESULT eDVBResourceManager::allocateRawChannel(eUsePtr<iDVBChannel> &channel, int slot_index)
702 ePtr<eDVBAllocatedFrontend> fe;
704 if (m_cached_channel)
706 m_cached_channel_state_changed_conn.disconnect();
708 m_releaseCachedChannelTimer->stop();
711 int err = allocateFrontendByIndex(fe, slot_index);
715 channel = new eDVBChannel(this, fe);
720 RESULT eDVBResourceManager::allocatePVRChannel(eUsePtr<iDVBPVRChannel> &channel)
722 ePtr<eDVBAllocatedDemux> demux;
724 if (m_cached_channel && m_releaseCachedChannelTimer->isActive())
726 m_cached_channel_state_changed_conn.disconnect();
728 m_releaseCachedChannelTimer->stop();
731 channel = new eDVBChannel(this, 0);
735 RESULT eDVBResourceManager::addChannel(const eDVBChannelID &chid, eDVBChannel *ch)
737 ePtr<iDVBFrontend> fe;
738 if (!ch->getFrontend(fe))
740 eDVBFrontend *frontend = (eDVBFrontend*)&(*fe);
741 if (frontend->is_simulate())
742 m_active_simulate_channels.push_back(active_channel(chid, ch));
745 m_active_channels.push_back(active_channel(chid, ch));
746 /* emit */ m_channelAdded(ch);
752 RESULT eDVBResourceManager::removeChannel(eDVBChannel *ch)
754 ePtr<iDVBFrontend> fe;
755 if (!ch->getFrontend(fe))
757 eDVBFrontend *frontend = (eDVBFrontend*)&(*fe);
758 std::list<active_channel> &active_channels = frontend->is_simulate() ? m_active_simulate_channels : m_active_channels;
760 for (std::list<active_channel>::iterator i(active_channels.begin()); i != active_channels.end();)
762 if (i->m_channel == ch)
764 i = active_channels.erase(i);
776 RESULT eDVBResourceManager::connectChannelAdded(const Slot1<void,eDVBChannel*> &channelAdded, ePtr<eConnection> &connection)
778 connection = new eConnection((eDVBResourceManager*)this, m_channelAdded.connect(channelAdded));
782 int eDVBResourceManager::canAllocateFrontend(ePtr<iDVBFrontendParameters> &feparm, bool simulate)
784 eSmartPtrList<eDVBRegisteredFrontend> &frontends = simulate ? m_simulate_frontend : m_frontend;
785 ePtr<eDVBRegisteredFrontend> best;
788 for (eSmartPtrList<eDVBRegisteredFrontend>::iterator i(frontends.begin()); i != frontends.end(); ++i)
791 int c = i->m_frontend->isCompatibleWith(feparm);
798 int tuner_type_channel_default(ePtr<iDVBChannelList> &channellist, const eDVBChannelID &chid)
802 ePtr<iDVBFrontendParameters> feparm;
803 if (!channellist->getChannelFrontendData(chid, feparm))
806 if (!feparm->getSystem(system))
810 case iDVBFrontend::feSatellite:
812 case iDVBFrontend::feCable:
814 case iDVBFrontend::feTerrestrial:
825 int eDVBResourceManager::canAllocateChannel(const eDVBChannelID &channelid, const eDVBChannelID& ignore, bool simulate)
827 std::list<active_channel> &active_channels = simulate ? m_active_simulate_channels : m_active_channels;
829 if (!simulate && m_cached_channel)
831 eDVBChannel *cache_chan = (eDVBChannel*)&(*m_cached_channel);
832 if(channelid==cache_chan->getChannelID())
833 return tuner_type_channel_default(m_list, channelid);
836 /* first, check if a channel is already existing. */
837 // eDebug("allocate channel.. %04x:%04x", channelid.transport_stream_id.get(), channelid.original_network_id.get());
838 for (std::list<active_channel>::iterator i(active_channels.begin()); i != active_channels.end(); ++i)
840 // eDebug("available channel.. %04x:%04x", i->m_channel_id.transport_stream_id.get(), i->m_channel_id.original_network_id.get());
841 if (i->m_channel_id == channelid)
843 // eDebug("found shared channel..");
844 return tuner_type_channel_default(m_list, channelid);
848 int *decremented_cached_channel_fe_usecount=NULL,
849 *decremented_fe_usecount=NULL;
851 for (std::list<active_channel>::iterator i(active_channels.begin()); i != active_channels.end(); ++i)
853 eSmartPtrList<eDVBRegisteredFrontend> &frontends = simulate ? m_simulate_frontend : m_frontend;
854 // eDebug("available channel.. %04x:%04x", i->m_channel_id.transport_stream_id.get(), i->m_channel_id.original_network_id.get());
855 if (i->m_channel_id == ignore)
857 eDVBChannel *channel = (eDVBChannel*) &(*i->m_channel);
858 // one eUsePtr<iDVBChannel> is used in eDVBServicePMTHandler
859 // another on eUsePtr<iDVBChannel> is used in the eDVBScan instance used in eDVBServicePMTHandler (for SDT scan)
860 // so we must check here if usecount is 3 (when the channel is equal to the cached channel)
861 // or 2 when the cached channel is not equal to the compared channel
862 if (channel == &(*m_cached_channel) ? channel->getUseCount() == 3 : channel->getUseCount() == 2) // channel only used once..
864 ePtr<iDVBFrontend> fe;
865 if (!i->m_channel->getFrontend(fe))
867 for (eSmartPtrList<eDVBRegisteredFrontend>::iterator ii(frontends.begin()); ii != frontends.end(); ++ii)
869 if ( &(*fe) == &(*ii->m_frontend) )
872 decremented_fe_usecount = &ii->m_inuse;
873 if (channel == &(*m_cached_channel))
874 decremented_cached_channel_fe_usecount = decremented_fe_usecount;
884 if (!decremented_cached_channel_fe_usecount)
886 if (m_cached_channel)
888 eDVBChannel *channel = (eDVBChannel*) &(*m_cached_channel);
889 if (channel->getUseCount() == 1)
891 ePtr<iDVBFrontend> fe;
892 if (!channel->getFrontend(fe))
894 eSmartPtrList<eDVBRegisteredFrontend> &frontends = simulate ? m_simulate_frontend : m_frontend;
895 for (eSmartPtrList<eDVBRegisteredFrontend>::iterator ii(frontends.begin()); ii != frontends.end(); ++ii)
897 if ( &(*fe) == &(*ii->m_frontend) )
900 decremented_cached_channel_fe_usecount = &ii->m_inuse;
909 decremented_cached_channel_fe_usecount=NULL;
911 ePtr<iDVBFrontendParameters> feparm;
915 eDebug("no channel list set!");
919 if (m_list->getChannelFrontendData(channelid, feparm))
921 eDebug("channel not found!");
925 ret = canAllocateFrontend(feparm, simulate);
928 if (decremented_fe_usecount)
929 ++(*decremented_fe_usecount);
930 if (decremented_cached_channel_fe_usecount)
931 ++(*decremented_cached_channel_fe_usecount);
936 bool eDVBResourceManager::canMeasureFrontendInputPower()
938 for (eSmartPtrList<eDVBRegisteredFrontend>::iterator i(m_frontend.begin()); i != m_frontend.end(); ++i)
940 return i->m_frontend->readInputpower() >= 0;
945 class eDVBChannelFilePush: public eFilePushThread
948 eDVBChannelFilePush() { setIFrameSearch(0); setTimebaseChange(0); }
949 void setIFrameSearch(int enabled) { m_iframe_search = enabled; m_iframe_state = 0; }
951 /* "timebase change" is for doing trickmode playback at an exact speed, even when pictures are skipped. */
952 /* you need to set it to 1/16 if you want 16x playback, for example. you need video master sync. */
953 void setTimebaseChange(int ratio) { m_timebase_change = ratio; } /* 16bit fixpoint, 0 for disable */
955 int m_iframe_search, m_iframe_state, m_pid;
956 int m_timebase_change;
957 int filterRecordData(const unsigned char *data, int len, size_t ¤t_span_remaining);
960 int eDVBChannelFilePush::filterRecordData(const unsigned char *_data, int len, size_t ¤t_span_remaining)
963 if (m_timebase_change)
965 eDebug("timebase change: %d", m_timebase_change);
967 for (offset = 0; offset < len; offset += 188)
969 unsigned char *pkt = (unsigned char*)_data + offset;
970 if (pkt[1] & 0x40) /* pusi */
972 if (pkt[3] & 0x20) // adaption field present?
973 pkt += pkt[4] + 4 + 1; /* skip adaption field and header */
975 pkt += 4; /* skip header */
976 if (pkt[0] || pkt[1] || (pkt[2] != 1))
978 eWarning("broken startcode");
984 if (pkt[7] & 0x80) // PTS present?
986 pts = ((unsigned long long)(pkt[ 9]&0xE)) << 29;
987 pts |= ((unsigned long long)(pkt[10]&0xFF)) << 22;
988 pts |= ((unsigned long long)(pkt[11]&0xFE)) << 14;
989 pts |= ((unsigned long long)(pkt[12]&0xFF)) << 7;
990 pts |= ((unsigned long long)(pkt[13]&0xFE)) >> 1;
994 RESULT r = m_tstools.fixupPTS(off, pts);
996 eWarning("fixup PTS while trickmode playback failed.\n");
999 int sec = pts / 90000;
1000 int frm = pts % 90000;
1008 // eDebug("original, fixed pts: %016llx %d:%02d:%02d:%02d:%05d", pts, d, hr, min, sec, frm);
1010 pts += 0x80000000LL;
1011 pts *= m_timebase_change;
1023 // eDebug("new pts (after timebase change): %016llx %d:%02d:%02d:%02d:%05d", pts, d, hr, min, sec, frm);
1031 pkt[9] |= (pts >> 29) & 0xE;
1032 pkt[10] |= (pts >> 22) & 0xFF;
1033 pkt[11] |= (pts >> 14) & 0xFE;
1034 pkt[12] |= (pts >> 7) & 0xFF;
1035 pkt[13] |= (pts << 1) & 0xFE;
1043 if (!m_iframe_search)
1046 unsigned char *data = (unsigned char*)_data; /* remove that const. we know what we are doing. */
1048 // eDebug("filterRecordData, size=%d (mod 188=%d), first byte is %02x", len, len %188, data[0]);
1050 unsigned char *d = data;
1051 while ((d + 3 < data + len) && (d = (unsigned char*)memmem(d, data + len - d, "\x00\x00\x01", 3)))
1053 int offset = d - data;
1054 int ts_offset = offset - offset % 188; /* offset to the start of TS packet */
1055 unsigned char *ts = data + ts_offset;
1056 int pid = ((ts[1] << 8) | ts[2]) & 0x1FFF;
1058 if ((d[3] == 0 || d[3] == 0x09 && d[-1] == 0 && (ts[1] & 0x40)) && (m_pid == pid)) /* picture start */
1060 int picture_type = (d[3]==0 ? (d[5] >> 3) & 7 : (d[4] >> 5) + 1);
1063 // eDebug("%d-frame at %d, offset in TS packet: %d, pid=%04x", picture_type, offset, offset % 188, pid);
1065 if (m_iframe_state == 1)
1067 /* we are allowing data, and stop allowing data on the next frame.
1068 we now found a frame. so stop here. */
1069 memset(data + offset, 0, 188 - (offset%188)); /* zero out rest of TS packet */
1070 current_span_remaining = 0;
1072 unsigned char *fts = ts + 188;
1073 while (fts < (data + len))
1076 fts[2] |= 0xff; /* drop packet */
1080 return len; // ts_offset + 188; /* deliver this packet, but not more. */
1083 if (picture_type != 1) /* we are only interested in I frames */
1086 unsigned char *fts = data;
1090 fts[2] |= 0xff; /* drop packet */
1097 } else if ((d[3] & 0xF0) == 0xE0) /* video stream */
1099 /* verify that this is actually a PES header, not just some ES data */
1100 if (ts[1] & 0x40) /* PUSI set */
1102 int payload_start = 4;
1103 if (ts[3] & 0x20) /* adaptation field present */
1104 payload_start += ts[4] + 1; /* skip AF */
1105 if (payload_start == (offset%188)) /* the 00 00 01 should be directly at the payload start, otherwise it's not a PES header */
1109 eDebug("now locked to pid %04x (%02x %02x %02x %02x)", pid, ts[0], ts[1], ts[2], ts[3]);
1117 d += 4; /* ignore */
1120 if (m_iframe_state == 1)
1123 return 0; /* we need find an iframe first */
1129 DEFINE_REF(eDVBChannel);
1131 eDVBChannel::eDVBChannel(eDVBResourceManager *mgr, eDVBAllocatedFrontend *frontend): m_state(state_idle), m_mgr(mgr)
1133 m_frontend = frontend;
1138 m_skipmode_n = m_skipmode_m = m_skipmode_frames = 0;
1141 m_frontend->get().connectStateChange(slot(*this, &eDVBChannel::frontendStateChanged), m_conn_frontendStateChanged);
1144 eDVBChannel::~eDVBChannel()
1147 m_mgr->removeChannel(this);
1152 void eDVBChannel::frontendStateChanged(iDVBFrontend*fe)
1154 int state, ourstate = 0;
1156 /* if we are already in shutdown, don't change state. */
1157 if (m_state == state_release)
1160 if (fe->getState(state))
1163 if (state == iDVBFrontend::stateLock)
1165 eDebug("OURSTATE: ok");
1166 ourstate = state_ok;
1167 } else if (state == iDVBFrontend::stateTuning)
1169 eDebug("OURSTATE: tuning");
1170 ourstate = state_tuning;
1171 } else if (state == iDVBFrontend::stateLostLock)
1173 /* on managed channels, we try to retune in order to re-acquire lock. */
1174 if (m_current_frontend_parameters)
1176 eDebug("OURSTATE: lost lock, trying to retune");
1177 ourstate = state_tuning;
1178 m_frontend->get().tune(*m_current_frontend_parameters);
1180 /* on unmanaged channels, we don't do this. the client will do this. */
1182 eDebug("OURSTATE: lost lock, unavailable now.");
1183 ourstate = state_unavailable;
1185 } else if (state == iDVBFrontend::stateFailed)
1187 eDebug("OURSTATE: failed");
1188 ourstate = state_failed;
1190 eFatal("state unknown");
1192 if (ourstate != m_state)
1195 m_stateChanged(this);
1199 void eDVBChannel::pvrEvent(int event)
1203 case eFilePushThread::evtEOF:
1204 eDebug("eDVBChannel: End of file!");
1205 m_event(this, evtEOF);
1207 case eFilePushThread::evtUser: /* start */
1209 m_event(this, evtSOF);
1214 void eDVBChannel::cueSheetEvent(int event)
1216 /* we might end up here if playing failed or stopped, but the client hasn't (yet) noted. */
1221 case eCueSheet::evtSeek:
1223 flushPVR(m_cue->m_decoding_demux);
1225 case eCueSheet::evtSkipmode:
1228 m_cue->m_lock.WrLock();
1229 m_cue->m_seek_requests.push_back(std::pair<int, pts_t>(1, 0)); /* resync */
1230 m_cue->m_lock.Unlock();
1231 eRdLocker l(m_cue->m_lock);
1232 if (m_cue->m_skipmode_ratio)
1234 int bitrate = m_tstools.calcBitrate(); /* in bits/s */
1235 eDebug("skipmode ratio is %lld:90000, bitrate is %d bit/s", m_cue->m_skipmode_ratio, bitrate);
1236 /* i agree that this might look a bit like black magic. */
1237 m_skipmode_n = 512*1024; /* must be 1 iframe at least. */
1238 m_skipmode_m = bitrate / 8 / 90000 * m_cue->m_skipmode_ratio / 8;
1239 m_skipmode_frames = m_cue->m_skipmode_ratio / 90000;
1240 m_skipmode_frames_remainder = 0;
1242 if (m_cue->m_skipmode_ratio < 0)
1243 m_skipmode_m -= m_skipmode_n;
1245 eDebug("resolved to: %d %d", m_skipmode_m, m_skipmode_n);
1247 if (abs(m_skipmode_m) < abs(m_skipmode_n))
1249 eWarning("something is wrong with this calculation");
1250 m_skipmode_frames = m_skipmode_n = m_skipmode_m = 0;
1254 eDebug("skipmode ratio is 0, normal play");
1255 m_skipmode_frames = m_skipmode_n = m_skipmode_m = 0;
1258 m_pvr_thread->setIFrameSearch(m_skipmode_n != 0);
1259 if (m_cue->m_skipmode_ratio != 0)
1260 m_pvr_thread->setTimebaseChange(0x10000 * 9000 / (m_cue->m_skipmode_ratio / 10)); /* negative values are also ok */
1262 m_pvr_thread->setTimebaseChange(0); /* normal playback */
1263 eDebug("flush pvr");
1264 flushPVR(m_cue->m_decoding_demux);
1268 case eCueSheet::evtSpanChanged:
1270 m_source_span.clear();
1271 for (std::list<std::pair<pts_t, pts_t> >::const_iterator i(m_cue->m_spans.begin()); i != m_cue->m_spans.end(); ++i)
1273 off_t offset_in, offset_out;
1274 pts_t pts_in = i->first, pts_out = i->second;
1275 if (m_tstools.getOffset(offset_in, pts_in, -1) || m_tstools.getOffset(offset_out, pts_out, 1))
1277 eDebug("span translation failed.\n");
1280 eDebug("source span: %llx .. %llx, translated to %llx..%llx", pts_in, pts_out, offset_in, offset_out);
1281 m_source_span.push_back(std::pair<off_t, off_t>(offset_in, offset_out));
1288 /* align toward zero */
1289 static inline long long align(long long x, int align)
1304 /* align toward zero */
1305 static inline long long align_with_len(long long x, int align, size_t &len)
1321 /* remember, this gets called from another thread. */
1322 void eDVBChannel::getNextSourceSpan(off_t current_offset, size_t bytes_read, off_t &start, size_t &size)
1324 const int blocksize = 188;
1325 unsigned int max = align(10*1024*1024, blocksize);
1326 current_offset = align(current_offset, blocksize);
1330 eDebug("no cue sheet. forcing normal play");
1331 start = current_offset;
1338 eDebug("skipmode %d:%d (x%d)", m_skipmode_m, m_skipmode_n, m_skipmode_frames);
1339 max = align(m_skipmode_n, blocksize);
1342 eDebug("getNextSourceSpan, current offset is %08llx, m_skipmode_m = %d!", current_offset, m_skipmode_m);
1343 int frame_skip_success = 0;
1347 int frames_to_skip = m_skipmode_frames + m_skipmode_frames_remainder;
1348 eDebug("we are at %llx, and we try to skip %d+%d frames from here", current_offset, m_skipmode_frames, m_skipmode_frames_remainder);
1350 off_t iframe_start = current_offset;
1351 int frames_skipped = frames_to_skip;
1352 if (!m_tstools.findNextPicture(iframe_start, iframe_len, frames_skipped))
1354 m_skipmode_frames_remainder = frames_to_skip - frames_skipped;
1355 eDebug("successfully skipped %d (out of %d, rem now %d) frames.", frames_skipped, frames_to_skip, m_skipmode_frames_remainder);
1356 current_offset = align_with_len(iframe_start, blocksize, iframe_len);
1357 max = align(iframe_len + 187, blocksize);
1358 frame_skip_success = 1;
1361 m_skipmode_frames_remainder = 0;
1362 eDebug("frame skipping failed, reverting to byte-skipping");
1366 if (!frame_skip_success)
1368 current_offset += align(m_skipmode_m, blocksize);
1372 eDebug("we are at %llx, and we try to find the iframe here:", current_offset);
1374 off_t iframe_start = current_offset;
1376 int direction = (m_skipmode_m < 0) ? -1 : +1;
1377 if (m_tstools.findFrame(iframe_start, iframe_len, direction))
1381 current_offset = align_with_len(iframe_start, blocksize, iframe_len);
1382 max = align(iframe_len, blocksize);
1387 m_cue->m_lock.RdLock();
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 (!m_cue->m_decoding_demux)
1415 eDebug("getNextSourceSpan, no decoding demux. couldn't seek to %llx... ignore request!", pts);
1416 start = current_offset;
1420 if (getCurrentPosition(m_cue->m_decoding_demux, now, 1))
1422 eDebug("seekTo: getCurrentPosition failed!");
1425 } else if (pts < 0) /* seek relative to end */
1428 if (!getLength(len))
1430 eDebug("seeking relative to end. len=%lld, seek = %lld", len, pts);
1434 eWarning("getLength failed - can't seek relative to end!");
1439 if (relative == 1) /* pts relative */
1450 if (relative == 2) /* AP relative */
1452 eDebug("AP relative seeking: %lld, at %lld", pts, now);
1454 if (m_tstools.getNextAccessPoint(nextap, now, pts))
1456 pts = now - 90000; /* approx. 1s */
1457 eDebug("AP relative seeking failed!");
1461 eDebug("next ap is %llx\n", pts);
1466 if (m_tstools.getOffset(offset, pts, -1))
1468 eDebug("get offset for pts=%lld failed!", pts);
1472 eDebug("ok, resolved skip (rel: %d, diff %lld), now at %08llx", relative, pts, offset);
1473 current_offset = align(offset, blocksize); /* in case tstools return non-aligned offset */
1476 m_cue->m_lock.Unlock();
1478 for (std::list<std::pair<off_t, off_t> >::const_iterator i(m_source_span.begin()); i != m_source_span.end(); ++i)
1480 long long aligned_start = align(i->first, blocksize);
1481 long long aligned_end = align(i->second, blocksize);
1483 if ((current_offset >= aligned_start) && (current_offset < aligned_end))
1485 start = current_offset;
1486 /* max can not exceed max(size_t). aligned_end - current_offset, however, can. */
1487 if ((aligned_end - current_offset) > max)
1490 size = aligned_end - current_offset;
1491 eDebug("HIT, %lld < %lld < %lld, size: %d", i->first, current_offset, i->second, size);
1494 if (current_offset < aligned_start)
1496 /* ok, our current offset is in an 'out' zone. */
1497 if ((m_skipmode_m >= 0) || (i == m_source_span.begin()))
1499 /* in normal playback, just start at the next zone. */
1502 /* size is not 64bit! */
1503 if ((i->second - i->first) > max)
1506 size = aligned_end - aligned_start;
1509 if (m_skipmode_m < 0)
1511 eDebug("reached SOF");
1514 m_pvr_thread->sendEvent(eFilePushThread::evtUser);
1518 /* when skipping reverse, however, choose the zone before. */
1520 eDebug("skip to previous block, which is %llx..%llx", i->first, i->second);
1523 aligned_start = align(i->first, blocksize);
1524 aligned_end = align(i->second, blocksize);
1526 if ((aligned_end - aligned_start) > max)
1529 len = aligned_end - aligned_start;
1531 start = aligned_end - len;
1532 eDebug("skipping to %llx, %d", start, len);
1535 eDebug("result: %llx, %x (%llx %llx)", start, size, aligned_start, aligned_end);
1540 if ((current_offset < -m_skipmode_m) && (m_skipmode_m < 0))
1542 eDebug("reached SOF");
1544 m_pvr_thread->sendEvent(eFilePushThread::evtUser);
1547 if (m_source_span.empty())
1549 start = current_offset;
1551 eDebug("NO CUESHEET. (%08llx, %d)", start, size);
1554 start = current_offset;
1560 void eDVBChannel::AddUse()
1562 if (++m_use_count > 1 && m_state == state_last_instance)
1565 m_stateChanged(this);
1569 void eDVBChannel::ReleaseUse()
1573 m_state = state_release;
1574 m_stateChanged(this);
1576 else if (m_use_count == 1)
1578 m_state = state_last_instance;
1579 m_stateChanged(this);
1583 RESULT eDVBChannel::setChannel(const eDVBChannelID &channelid, ePtr<iDVBFrontendParameters> &feparm)
1586 m_mgr->removeChannel(this);
1593 eDebug("no frontend to tune!");
1597 m_channel_id = channelid;
1598 m_mgr->addChannel(channelid, this);
1599 m_state = state_tuning;
1600 /* if tuning fails, shutdown the channel immediately. */
1602 res = m_frontend->get().tune(*feparm);
1603 m_current_frontend_parameters = feparm;
1607 m_state = state_release;
1608 m_stateChanged(this);
1615 RESULT eDVBChannel::connectStateChange(const Slot1<void,iDVBChannel*> &stateChange, ePtr<eConnection> &connection)
1617 connection = new eConnection((iDVBChannel*)this, m_stateChanged.connect(stateChange));
1621 RESULT eDVBChannel::connectEvent(const Slot2<void,iDVBChannel*,int> &event, ePtr<eConnection> &connection)
1623 connection = new eConnection((iDVBChannel*)this, m_event.connect(event));
1627 RESULT eDVBChannel::getState(int &state)
1633 RESULT eDVBChannel::setCIRouting(const eDVBCIRouting &routing)
1638 void eDVBChannel::SDTready(int result)
1640 ePyObject args = PyTuple_New(2), ret;
1644 for (std::vector<ServiceDescriptionSection*>::const_iterator i = m_SDT->getSections().begin(); i != m_SDT->getSections().end(); ++i)
1647 PyTuple_SET_ITEM(args, 0, PyInt_FromLong((*i)->getTransportStreamId()));
1648 PyTuple_SET_ITEM(args, 1, PyInt_FromLong((*i)->getOriginalNetworkId()));
1654 PyTuple_SET_ITEM(args, 0, Py_None);
1655 PyTuple_SET_ITEM(args, 1, Py_None);
1659 ret = PyObject_CallObject(m_tsid_onid_callback, args);
1663 Py_DECREF(m_tsid_onid_callback);
1664 m_tsid_onid_callback = ePyObject();
1665 m_tsid_onid_demux = 0;
1669 int eDVBChannel::reserveDemux()
1671 ePtr<iDVBDemux> dmx;
1672 if (!getDemux(dmx, 0))
1675 if (!dmx->getCADemuxID(id))
1681 RESULT eDVBChannel::requestTsidOnid(ePyObject callback)
1683 if (PyCallable_Check(callback))
1685 if (!getDemux(m_tsid_onid_demux, 0))
1687 m_SDT = new eTable<ServiceDescriptionSection>;
1688 CONNECT(m_SDT->tableReady, eDVBChannel::SDTready);
1689 if (m_SDT->start(m_tsid_onid_demux, eDVBSDTSpec()))
1691 m_tsid_onid_demux = 0;
1696 Py_INCREF(callback);
1697 m_tsid_onid_callback = callback;
1705 RESULT eDVBChannel::getDemux(ePtr<iDVBDemux> &demux, int cap)
1707 ePtr<eDVBAllocatedDemux> &our_demux = (cap & capDecode) ? m_decoder_demux : m_demux;
1713 if (m_mgr->allocateDemux(m_frontend ? (eDVBRegisteredFrontend*)*m_frontend : (eDVBRegisteredFrontend*)0, our_demux, cap))
1718 /* don't hold a reference to the decoding demux, we don't need it. */
1720 /* FIXME: by dropping the 'allocated demux' in favour of the 'iDVBDemux',
1721 the refcount is lost. thus, decoding demuxes are never allocated.
1723 this poses a big problem for PiP. */
1725 if (cap & capHoldDecodeReference) // this is set in eDVBResourceManager::allocateDemux for Dm500HD/DM800 and DM8000
1727 else if (cap & capDecode)
1736 RESULT eDVBChannel::getFrontend(ePtr<iDVBFrontend> &frontend)
1741 frontend = &m_frontend->get();
1747 RESULT eDVBChannel::getCurrentFrontendParameters(ePtr<iDVBFrontendParameters> ¶m)
1749 param = m_current_frontend_parameters;
1753 RESULT eDVBChannel::playFile(const char *file)
1755 ASSERT(!m_frontend);
1758 m_pvr_thread->stop();
1759 delete m_pvr_thread;
1763 m_tstools.openFile(file);
1765 /* DON'T EVEN THINK ABOUT FIXING THIS. FIX THE ATI SOURCES FIRST,
1766 THEN DO A REAL FIX HERE! */
1768 if (m_pvr_fd_dst < 0)
1770 /* (this codepath needs to be improved anyway.) */
1771 #if HAVE_DVB_API_VERSION < 3
1772 m_pvr_fd_dst = open("/dev/pvr", O_WRONLY);
1774 m_pvr_fd_dst = open("/dev/misc/pvr", O_WRONLY);
1776 if (m_pvr_fd_dst < 0)
1778 eDebug("can't open /dev/misc/pvr - you need to buy the new(!) $$$ box! (%m)"); // or wait for the driver to be improved.
1783 m_pvr_thread = new eDVBChannelFilePush();
1784 m_pvr_thread->enablePVRCommit(1);
1785 m_pvr_thread->setStreamMode(1);
1786 m_pvr_thread->setScatterGather(this);
1788 m_event(this, evtPreStart);
1790 if (m_pvr_thread->start(file, m_pvr_fd_dst))
1792 delete m_pvr_thread;
1794 ::close(m_pvr_fd_dst);
1796 eDebug("can't open PVR file %s (%m)", file);
1799 CONNECT(m_pvr_thread->m_event, eDVBChannel::pvrEvent);
1802 m_stateChanged(this);
1807 void eDVBChannel::stopFile()
1811 m_pvr_thread->stop();
1812 delete m_pvr_thread;
1815 if (m_pvr_fd_dst >= 0)
1816 ::close(m_pvr_fd_dst);
1819 void eDVBChannel::setCueSheet(eCueSheet *cuesheet)
1821 m_conn_cueSheetEvent = 0;
1824 m_cue->connectEvent(slot(*this, &eDVBChannel::cueSheetEvent), m_conn_cueSheetEvent);
1827 RESULT eDVBChannel::getLength(pts_t &len)
1829 return m_tstools.calcLen(len);
1832 RESULT eDVBChannel::getCurrentPosition(iDVBDemux *decoding_demux, pts_t &pos, int mode)
1834 if (!decoding_demux)
1841 if (mode == 0) /* demux */
1843 r = decoding_demux->getSTC(now, 0);
1846 eDebug("demux getSTC failed");
1850 now = pos; /* fixup supplied */
1852 off_t off = 0; /* TODO: fixme */
1853 r = m_tstools.fixupPTS(off, now);
1856 eDebug("fixup PTS failed");
1865 void eDVBChannel::flushPVR(iDVBDemux *decoding_demux)
1867 /* when seeking, we have to ensure that all buffers are flushed.
1868 there are basically 3 buffers:
1869 a.) the filepush's internal buffer
1870 b.) the PVR buffer (before demux)
1871 c.) the ratebuffer (after demux)
1873 it's important to clear them in the correct order, otherwise
1874 the ratebuffer (for example) would immediately refill from
1875 the not-yet-flushed PVR buffer.
1878 m_pvr_thread->pause();
1879 /* flush internal filepush buffer */
1880 m_pvr_thread->flush();
1881 /* HACK: flush PVR buffer */
1882 ::ioctl(m_pvr_fd_dst, 0);
1884 /* flush ratebuffers (video, audio) */
1886 decoding_demux->flush();
1888 /* demux will also flush all decoder.. */
1889 /* resume will re-query the SG */
1890 m_pvr_thread->resume();
1893 DEFINE_REF(eCueSheet);
1895 eCueSheet::eCueSheet()
1897 m_skipmode_ratio = 0;
1900 void eCueSheet::seekTo(int relative, const pts_t &pts)
1903 m_seek_requests.push_back(std::pair<int, pts_t>(relative, pts));
1908 void eCueSheet::clear()
1915 void eCueSheet::addSourceSpan(const pts_t &begin, const pts_t &end)
1917 ASSERT(begin < end);
1919 m_spans.push_back(std::pair<pts_t, pts_t>(begin, end));
1923 void eCueSheet::commitSpans()
1925 m_event(evtSpanChanged);
1928 void eCueSheet::setSkipmode(const pts_t &ratio)
1931 m_skipmode_ratio = ratio;
1933 m_event(evtSkipmode);
1936 void eCueSheet::setDecodingDemux(iDVBDemux *demux, iTSMPEGDecoder *decoder)
1938 m_decoding_demux = demux;
1939 m_decoder = decoder;
1942 RESULT eCueSheet::connectEvent(const Slot1<void,int> &event, ePtr<eConnection> &connection)
1944 connection = new eConnection(this, m_event.connect(event));