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))
101 else if (!strncmp(tmp, "dm7020hd\n", rd))
102 m_boxtype = DM7020HD;
104 eDebug("boxtype detection via /proc/stb/info not possible... use fallback via demux count!\n");
105 if (m_demux.size() == 3)
107 else if (m_demux.size() < 5)
113 eDebug("found %zd adapter, %zd frontends(%zd sim) and %zd demux, boxtype %d",
114 m_adapter.size(), m_frontend.size(), m_simulate_frontend.size(), m_demux.size(), m_boxtype);
116 eDVBCAService::registerChannelCallback(this);
118 CONNECT(m_releaseCachedChannelTimer->timeout, eDVBResourceManager::releaseCachedChannel);
121 void eDVBResourceManager::feStateChanged()
124 for (eSmartPtrList<eDVBRegisteredFrontend>::iterator i(m_frontend.begin()); i != m_frontend.end(); ++i)
126 mask |= ( 1 << i->m_frontend->getSlotID() );
127 /* emit */ frontendUseMaskChanged(mask);
130 DEFINE_REF(eDVBAdapterLinux);
131 eDVBAdapterLinux::eDVBAdapterLinux(int nr): m_nr(nr)
136 eDebug("scanning for frontends..");
141 #if HAVE_DVB_API_VERSION < 3
142 sprintf(filename, "/dev/dvb/card%d/frontend%d", m_nr, num_fe);
144 sprintf(filename, "/dev/dvb/adapter%d/frontend%d", m_nr, num_fe);
146 if (stat(filename, &s))
148 ePtr<eDVBFrontend> fe;
152 fe = new eDVBFrontend(m_nr, num_fe, ok);
154 m_frontend.push_back(fe);
158 fe = new eDVBFrontend(m_nr, num_fe, ok, true);
160 m_simulate_frontend.push_back(fe);
171 #if HAVE_DVB_API_VERSION < 3
172 sprintf(filename, "/dev/dvb/card%d/demux%d", m_nr, num_demux);
174 sprintf(filename, "/dev/dvb/adapter%d/demux%d", m_nr, num_demux);
176 if (stat(filename, &s))
178 ePtr<eDVBDemux> demux;
180 demux = new eDVBDemux(m_nr, num_demux);
181 m_demux.push_back(demux);
187 int eDVBAdapterLinux::getNumDemux()
189 return m_demux.size();
192 RESULT eDVBAdapterLinux::getDemux(ePtr<eDVBDemux> &demux, int nr)
194 eSmartPtrList<eDVBDemux>::iterator i(m_demux.begin());
195 while (nr && (i != m_demux.end()))
201 if (i != m_demux.end())
209 int eDVBAdapterLinux::getNumFrontends()
211 return m_frontend.size();
214 RESULT eDVBAdapterLinux::getFrontend(ePtr<eDVBFrontend> &fe, int nr, bool simulate)
216 eSmartPtrList<eDVBFrontend>::iterator i(simulate ? m_simulate_frontend.begin() : m_frontend.begin());
217 while (nr && (i != m_frontend.end()))
223 if (i != m_frontend.end())
231 int eDVBAdapterLinux::exist(int nr)
235 #if HAVE_DVB_API_VERSION < 3
236 sprintf(filename, "/dev/dvb/card%d", nr);
238 sprintf(filename, "/dev/dvb/adapter%d", nr);
240 if (!stat(filename, &s))
245 eDVBResourceManager::~eDVBResourceManager()
247 if (instance == this)
251 void eDVBResourceManager::addAdapter(iDVBAdapter *adapter)
253 int num_fe = adapter->getNumFrontends();
254 int num_demux = adapter->getNumDemux();
256 m_adapter.push_back(adapter);
259 for (i=0; i<num_demux; ++i)
261 ePtr<eDVBDemux> demux;
262 if (!adapter->getDemux(demux, i))
263 m_demux.push_back(new eDVBRegisteredDemux(demux, adapter));
266 ePtr<eDVBRegisteredFrontend> prev_dvbt_frontend;
267 for (i=0; i<num_fe; ++i)
269 ePtr<eDVBFrontend> frontend;
270 if (!adapter->getFrontend(frontend, i))
273 frontend->getFrontendType(frontendType);
274 eDVBRegisteredFrontend *new_fe = new eDVBRegisteredFrontend(frontend, adapter);
275 CONNECT(new_fe->stateChanged, eDVBResourceManager::feStateChanged);
276 m_frontend.push_back(new_fe);
277 frontend->setSEC(m_sec);
278 // we must link all dvb-t frontends ( for active antenna voltage )
279 if (frontendType == iDVBFrontend::feTerrestrial)
281 if (prev_dvbt_frontend)
283 prev_dvbt_frontend->m_frontend->setData(eDVBFrontend::LINKED_NEXT_PTR, (long)new_fe);
284 frontend->setData(eDVBFrontend::LINKED_PREV_PTR, (long)&(*prev_dvbt_frontend));
286 prev_dvbt_frontend = new_fe;
291 prev_dvbt_frontend = 0;
292 for (i=0; i<num_fe; ++i)
294 ePtr<eDVBFrontend> frontend;
295 if (!adapter->getFrontend(frontend, i, true))
298 frontend->getFrontendType(frontendType);
299 eDVBRegisteredFrontend *new_fe = new eDVBRegisteredFrontend(frontend, adapter);
300 // CONNECT(new_fe->stateChanged, eDVBResourceManager::feStateChanged);
301 m_simulate_frontend.push_back(new_fe);
302 frontend->setSEC(m_sec);
303 // we must link all dvb-t frontends ( for active antenna voltage )
304 if (frontendType == iDVBFrontend::feTerrestrial)
306 if (prev_dvbt_frontend)
308 prev_dvbt_frontend->m_frontend->setData(eDVBFrontend::LINKED_NEXT_PTR, (long)new_fe);
309 frontend->setData(eDVBFrontend::LINKED_PREV_PTR, (long)&(*prev_dvbt_frontend));
311 prev_dvbt_frontend = new_fe;
318 PyObject *eDVBResourceManager::setFrontendSlotInformations(ePyObject list)
320 if (!PyList_Check(list))
322 PyErr_SetString(PyExc_StandardError, "eDVBResourceManager::setFrontendSlotInformations argument should be a python list");
325 unsigned int assigned=0;
326 for (eSmartPtrList<eDVBRegisteredFrontend>::iterator i(m_frontend.begin()); i != m_frontend.end(); ++i)
329 while (pos < PyList_Size(list)) {
330 ePyObject obj = PyList_GET_ITEM(list, pos++);
331 if (!i->m_frontend->setSlotInfo(obj))
337 if (assigned != m_frontend.size()) {
339 sprintf(blasel, "eDVBResourceManager::setFrontendSlotInformations .. assigned %zd socket informations, but %d registered frontends!",
340 m_frontend.size(), assigned);
341 PyErr_SetString(PyExc_StandardError, blasel);
344 for (eSmartPtrList<eDVBRegisteredFrontend>::iterator i(m_simulate_frontend.begin()); i != m_simulate_frontend.end(); ++i)
347 while (pos < PyList_Size(list)) {
348 ePyObject obj = PyList_GET_ITEM(list, pos++);
349 if (!i->m_frontend->setSlotInfo(obj))
357 RESULT eDVBResourceManager::allocateFrontend(ePtr<eDVBAllocatedFrontend> &fe, ePtr<iDVBFrontendParameters> &feparm, bool simulate)
359 eSmartPtrList<eDVBRegisteredFrontend> &frontends = simulate ? m_simulate_frontend : m_frontend;
360 ePtr<eDVBRegisteredFrontend> best;
364 for (eSmartPtrList<eDVBRegisteredFrontend>::iterator i(frontends.begin()); i != frontends.end(); ++i)
366 int c = i->m_frontend->isCompatibleWith(feparm);
368 if (c) /* if we have at least one frontend which is compatible with the source, flag this. */
373 // eDebug("Slot %d, score %d", i->m_frontend->getSlotID(), c);
381 // eDebug("Slot %d, score %d... but BUSY!!!!!!!!!!!", i->m_frontend->getSlotID(), c);
386 fe = new eDVBAllocatedFrontend(best);
393 return errAllSourcesBusy;
395 return errNoSourceFound;
398 RESULT eDVBResourceManager::allocateFrontendByIndex(ePtr<eDVBAllocatedFrontend> &fe, int slot_index)
400 int err = errNoSourceFound;
401 for (eSmartPtrList<eDVBRegisteredFrontend>::iterator i(m_frontend.begin()); i != m_frontend.end(); ++i)
402 if (!i->m_inuse && i->m_frontend->getSlotID() == slot_index)
404 // check if another slot linked to this is in use
406 i->m_frontend->getData(eDVBFrontend::SATPOS_DEPENDS_PTR, tmp);
409 eDVBRegisteredFrontend *satpos_depends_to_fe = (eDVBRegisteredFrontend *)tmp;
410 if (satpos_depends_to_fe->m_inuse)
412 eDebug("another satpos depending frontend is in use.. so allocateFrontendByIndex not possible!");
413 err = errAllSourcesBusy;
414 goto alloc_fe_by_id_not_possible;
417 else // check linked tuners
419 i->m_frontend->getData(eDVBFrontend::LINKED_NEXT_PTR, tmp);
422 eDVBRegisteredFrontend *next = (eDVBRegisteredFrontend *) tmp;
425 eDebug("another linked frontend is in use.. so allocateFrontendByIndex not possible!");
426 err = errAllSourcesBusy;
427 goto alloc_fe_by_id_not_possible;
429 next->m_frontend->getData(eDVBFrontend::LINKED_NEXT_PTR, tmp);
431 i->m_frontend->getData(eDVBFrontend::LINKED_PREV_PTR, tmp);
434 eDVBRegisteredFrontend *prev = (eDVBRegisteredFrontend *) tmp;
437 eDebug("another linked frontend is in use.. so allocateFrontendByIndex not possible!");
438 err = errAllSourcesBusy;
439 goto alloc_fe_by_id_not_possible;
441 prev->m_frontend->getData(eDVBFrontend::LINKED_PREV_PTR, tmp);
444 fe = new eDVBAllocatedFrontend(i);
447 alloc_fe_by_id_not_possible:
452 #define capHoldDecodeReference 64
454 RESULT eDVBResourceManager::allocateDemux(eDVBRegisteredFrontend *fe, ePtr<eDVBAllocatedDemux> &demux, int &cap)
456 /* find first unused demux which is on same adapter as frontend (or any, if PVR)
457 never use the first one unless we need a decoding demux. */
459 eDebug("allocate demux");
460 eSmartPtrList<eDVBRegisteredDemux>::iterator i(m_demux.begin());
464 if (i == m_demux.end())
467 ePtr<eDVBRegisteredDemux> unused;
469 if (m_boxtype == DM800 || m_boxtype == DM500HD || m_boxtype == DM800SE) // dm800 / 500hd
471 cap |= capHoldDecodeReference; // this is checked in eDVBChannel::getDemux
472 for (; i != m_demux.end(); ++i, ++n)
483 if (i->m_adapter == fe->m_adapter &&
484 i->m_demux->getSource() == fe->m_frontend->getDVBID())
486 demux = new eDVBAllocatedDemux(i);
490 else if (i->m_demux->getSource() == -1) // PVR
492 demux = new eDVBAllocatedDemux(i);
498 else if (m_boxtype == DM7025) // ATI
500 /* FIXME: hardware demux policy */
501 if (!(cap & iDVBChannel::capDecode))
503 if (m_demux.size() > 2) /* assumed to be true, otherwise we have lost anyway */
510 for (; i != m_demux.end(); ++i, ++n)
512 int is_decode = n < 2;
514 int in_use = is_decode ? (i->m_demux->getRefCount() != 2) : i->m_inuse;
516 if ((!in_use) && ((!fe) || (i->m_adapter == fe->m_adapter)))
518 if ((cap & iDVBChannel::capDecode) && !is_decode)
525 else if (m_boxtype == DM8000 || m_boxtype == DM7020HD)
527 cap |= capHoldDecodeReference; // this is checked in eDVBChannel::getDemux
528 for (; i != m_demux.end(); ++i, ++n)
537 else if (i->m_adapter == fe->m_adapter &&
538 i->m_demux->getSource() == fe->m_frontend->getDVBID())
540 demux = new eDVBAllocatedDemux(i);
544 else if (n == 4) // always use demux4 for PVR (demux 4 can not descramble...)
547 demux = new eDVBAllocatedDemux(i);
557 demux = new eDVBAllocatedDemux(unused);
559 demux->get().setSourceFrontend(fe->m_frontend->getDVBID());
561 demux->get().setSourcePVR(0);
565 eDebug("demux not found");
569 RESULT eDVBResourceManager::setChannelList(iDVBChannelList *list)
575 RESULT eDVBResourceManager::getChannelList(ePtr<iDVBChannelList> &list)
584 #define eDebugNoSimulate(x...) \
591 // eDebugNoNewLine("SIMULATE:"); \
596 RESULT eDVBResourceManager::allocateChannel(const eDVBChannelID &channelid, eUsePtr<iDVBChannel> &channel, bool simulate)
598 /* first, check if a channel is already existing. */
599 std::list<active_channel> &active_channels = simulate ? m_active_simulate_channels : m_active_channels;
601 if (!simulate && m_cached_channel)
603 eDVBChannel *cache_chan = (eDVBChannel*)&(*m_cached_channel);
604 if(channelid==cache_chan->getChannelID())
606 eDebug("use cached_channel");
607 channel = m_cached_channel;
610 m_cached_channel_state_changed_conn.disconnect();
612 m_releaseCachedChannelTimer->stop();
615 eDebugNoSimulate("allocate channel.. %04x:%04x", channelid.transport_stream_id.get(), channelid.original_network_id.get());
616 for (std::list<active_channel>::iterator i(active_channels.begin()); i != active_channels.end(); ++i)
618 eDebugNoSimulate("available channel.. %04x:%04x", i->m_channel_id.transport_stream_id.get(), i->m_channel_id.original_network_id.get());
619 if (i->m_channel_id == channelid)
621 eDebugNoSimulate("found shared channel..");
622 channel = i->m_channel;
627 /* no currently available channel is tuned to this channelid. create a new one, if possible. */
631 eDebugNoSimulate("no channel list set!");
632 return errNoChannelList;
635 ePtr<iDVBFrontendParameters> feparm;
636 if (m_list->getChannelFrontendData(channelid, feparm))
638 eDebugNoSimulate("channel not found!");
639 return errChannelNotInList;
642 /* allocate a frontend. */
644 ePtr<eDVBAllocatedFrontend> fe;
646 int err = allocateFrontend(fe, feparm, simulate);
651 ePtr<eDVBChannel> ch = new eDVBChannel(this, fe);
653 res = ch->setChannel(channelid, feparm);
657 return errChidNotFound;
664 m_cached_channel = channel = ch;
665 m_cached_channel_state_changed_conn =
666 CONNECT(ch->m_stateChanged,eDVBResourceManager::DVBChannelStateChanged);
672 void eDVBResourceManager::DVBChannelStateChanged(iDVBChannel *chan)
675 chan->getState(state);
678 case iDVBChannel::state_release:
679 case iDVBChannel::state_ok:
681 eDebug("stop release channel timer");
682 m_releaseCachedChannelTimer->stop();
685 case iDVBChannel::state_last_instance:
687 eDebug("start release channel timer");
688 m_releaseCachedChannelTimer->start(3000, true);
691 default: // ignore all other events
696 void eDVBResourceManager::releaseCachedChannel()
698 eDebug("release cached channel (timer timeout)");
702 RESULT eDVBResourceManager::allocateRawChannel(eUsePtr<iDVBChannel> &channel, int slot_index)
704 ePtr<eDVBAllocatedFrontend> fe;
706 if (m_cached_channel)
708 m_cached_channel_state_changed_conn.disconnect();
710 m_releaseCachedChannelTimer->stop();
713 int err = allocateFrontendByIndex(fe, slot_index);
717 channel = new eDVBChannel(this, fe);
722 RESULT eDVBResourceManager::allocatePVRChannel(eUsePtr<iDVBPVRChannel> &channel)
724 ePtr<eDVBAllocatedDemux> demux;
726 if (m_cached_channel && m_releaseCachedChannelTimer->isActive())
728 m_cached_channel_state_changed_conn.disconnect();
730 m_releaseCachedChannelTimer->stop();
733 channel = new eDVBChannel(this, 0);
737 RESULT eDVBResourceManager::addChannel(const eDVBChannelID &chid, eDVBChannel *ch)
739 ePtr<iDVBFrontend> fe;
740 if (!ch->getFrontend(fe))
742 eDVBFrontend *frontend = (eDVBFrontend*)&(*fe);
743 if (frontend->is_simulate())
744 m_active_simulate_channels.push_back(active_channel(chid, ch));
747 m_active_channels.push_back(active_channel(chid, ch));
748 /* emit */ m_channelAdded(ch);
754 RESULT eDVBResourceManager::removeChannel(eDVBChannel *ch)
756 ePtr<iDVBFrontend> fe;
757 if (!ch->getFrontend(fe))
759 eDVBFrontend *frontend = (eDVBFrontend*)&(*fe);
760 std::list<active_channel> &active_channels = frontend->is_simulate() ? m_active_simulate_channels : m_active_channels;
762 for (std::list<active_channel>::iterator i(active_channels.begin()); i != active_channels.end();)
764 if (i->m_channel == ch)
766 i = active_channels.erase(i);
778 RESULT eDVBResourceManager::connectChannelAdded(const Slot1<void,eDVBChannel*> &channelAdded, ePtr<eConnection> &connection)
780 connection = new eConnection((eDVBResourceManager*)this, m_channelAdded.connect(channelAdded));
784 int eDVBResourceManager::canAllocateFrontend(ePtr<iDVBFrontendParameters> &feparm, bool simulate)
786 eSmartPtrList<eDVBRegisteredFrontend> &frontends = simulate ? m_simulate_frontend : m_frontend;
787 ePtr<eDVBRegisteredFrontend> best;
790 for (eSmartPtrList<eDVBRegisteredFrontend>::iterator i(frontends.begin()); i != frontends.end(); ++i)
793 int c = i->m_frontend->isCompatibleWith(feparm);
800 int tuner_type_channel_default(ePtr<iDVBChannelList> &channellist, const eDVBChannelID &chid)
804 ePtr<iDVBFrontendParameters> feparm;
805 if (!channellist->getChannelFrontendData(chid, feparm))
808 if (!feparm->getSystem(system))
812 case iDVBFrontend::feSatellite:
814 case iDVBFrontend::feCable:
816 case iDVBFrontend::feTerrestrial:
827 int eDVBResourceManager::canAllocateChannel(const eDVBChannelID &channelid, const eDVBChannelID& ignore, bool simulate)
829 std::list<active_channel> &active_channels = simulate ? m_active_simulate_channels : m_active_channels;
831 if (!simulate && m_cached_channel)
833 eDVBChannel *cache_chan = (eDVBChannel*)&(*m_cached_channel);
834 if(channelid==cache_chan->getChannelID())
835 return tuner_type_channel_default(m_list, channelid);
838 /* first, check if a channel is already existing. */
839 // eDebug("allocate channel.. %04x:%04x", channelid.transport_stream_id.get(), channelid.original_network_id.get());
840 for (std::list<active_channel>::iterator i(active_channels.begin()); i != active_channels.end(); ++i)
842 // eDebug("available channel.. %04x:%04x", i->m_channel_id.transport_stream_id.get(), i->m_channel_id.original_network_id.get());
843 if (i->m_channel_id == channelid)
845 // eDebug("found shared channel..");
846 return tuner_type_channel_default(m_list, channelid);
850 int *decremented_cached_channel_fe_usecount=NULL,
851 *decremented_fe_usecount=NULL;
853 for (std::list<active_channel>::iterator i(active_channels.begin()); i != active_channels.end(); ++i)
855 eSmartPtrList<eDVBRegisteredFrontend> &frontends = simulate ? m_simulate_frontend : m_frontend;
856 // eDebug("available channel.. %04x:%04x", i->m_channel_id.transport_stream_id.get(), i->m_channel_id.original_network_id.get());
857 if (i->m_channel_id == ignore)
859 eDVBChannel *channel = (eDVBChannel*) &(*i->m_channel);
860 // one eUsePtr<iDVBChannel> is used in eDVBServicePMTHandler
861 // another on eUsePtr<iDVBChannel> is used in the eDVBScan instance used in eDVBServicePMTHandler (for SDT scan)
862 // so we must check here if usecount is 3 (when the channel is equal to the cached channel)
863 // or 2 when the cached channel is not equal to the compared channel
864 if (channel == &(*m_cached_channel) ? channel->getUseCount() == 3 : channel->getUseCount() == 2) // channel only used once..
866 ePtr<iDVBFrontend> fe;
867 if (!i->m_channel->getFrontend(fe))
869 for (eSmartPtrList<eDVBRegisteredFrontend>::iterator ii(frontends.begin()); ii != frontends.end(); ++ii)
871 if ( &(*fe) == &(*ii->m_frontend) )
874 decremented_fe_usecount = &ii->m_inuse;
875 if (channel == &(*m_cached_channel))
876 decremented_cached_channel_fe_usecount = decremented_fe_usecount;
886 if (!decremented_cached_channel_fe_usecount)
888 if (m_cached_channel)
890 eDVBChannel *channel = (eDVBChannel*) &(*m_cached_channel);
891 if (channel->getUseCount() == 1)
893 ePtr<iDVBFrontend> fe;
894 if (!channel->getFrontend(fe))
896 eSmartPtrList<eDVBRegisteredFrontend> &frontends = simulate ? m_simulate_frontend : m_frontend;
897 for (eSmartPtrList<eDVBRegisteredFrontend>::iterator ii(frontends.begin()); ii != frontends.end(); ++ii)
899 if ( &(*fe) == &(*ii->m_frontend) )
902 decremented_cached_channel_fe_usecount = &ii->m_inuse;
911 decremented_cached_channel_fe_usecount=NULL;
913 ePtr<iDVBFrontendParameters> feparm;
917 eDebug("no channel list set!");
921 if (m_list->getChannelFrontendData(channelid, feparm))
923 eDebug("channel not found!");
927 ret = canAllocateFrontend(feparm, simulate);
930 if (decremented_fe_usecount)
931 ++(*decremented_fe_usecount);
932 if (decremented_cached_channel_fe_usecount)
933 ++(*decremented_cached_channel_fe_usecount);
938 bool eDVBResourceManager::canMeasureFrontendInputPower()
940 for (eSmartPtrList<eDVBRegisteredFrontend>::iterator i(m_frontend.begin()); i != m_frontend.end(); ++i)
942 return i->m_frontend->readInputpower() >= 0;
947 class eDVBChannelFilePush: public eFilePushThread
950 eDVBChannelFilePush() { setIFrameSearch(0); setTimebaseChange(0); }
951 void setIFrameSearch(int enabled) { m_iframe_search = enabled; m_iframe_state = 0; }
953 /* "timebase change" is for doing trickmode playback at an exact speed, even when pictures are skipped. */
954 /* you need to set it to 1/16 if you want 16x playback, for example. you need video master sync. */
955 void setTimebaseChange(int ratio) { m_timebase_change = ratio; } /* 16bit fixpoint, 0 for disable */
957 int m_iframe_search, m_iframe_state, m_pid;
958 int m_timebase_change;
959 int filterRecordData(const unsigned char *data, int len, size_t ¤t_span_remaining);
962 int eDVBChannelFilePush::filterRecordData(const unsigned char *_data, int len, size_t ¤t_span_remaining)
965 if (m_timebase_change)
967 eDebug("timebase change: %d", m_timebase_change);
969 for (offset = 0; offset < len; offset += 188)
971 unsigned char *pkt = (unsigned char*)_data + offset;
972 if (pkt[1] & 0x40) /* pusi */
974 if (pkt[3] & 0x20) // adaption field present?
975 pkt += pkt[4] + 4 + 1; /* skip adaption field and header */
977 pkt += 4; /* skip header */
978 if (pkt[0] || pkt[1] || (pkt[2] != 1))
980 eWarning("broken startcode");
986 if (pkt[7] & 0x80) // PTS present?
988 pts = ((unsigned long long)(pkt[ 9]&0xE)) << 29;
989 pts |= ((unsigned long long)(pkt[10]&0xFF)) << 22;
990 pts |= ((unsigned long long)(pkt[11]&0xFE)) << 14;
991 pts |= ((unsigned long long)(pkt[12]&0xFF)) << 7;
992 pts |= ((unsigned long long)(pkt[13]&0xFE)) >> 1;
996 RESULT r = m_tstools.fixupPTS(off, pts);
998 eWarning("fixup PTS while trickmode playback failed.\n");
1001 int sec = pts / 90000;
1002 int frm = pts % 90000;
1010 // eDebug("original, fixed pts: %016llx %d:%02d:%02d:%02d:%05d", pts, d, hr, min, sec, frm);
1012 pts += 0x80000000LL;
1013 pts *= m_timebase_change;
1025 // eDebug("new pts (after timebase change): %016llx %d:%02d:%02d:%02d:%05d", pts, d, hr, min, sec, frm);
1033 pkt[9] |= (pts >> 29) & 0xE;
1034 pkt[10] |= (pts >> 22) & 0xFF;
1035 pkt[11] |= (pts >> 14) & 0xFE;
1036 pkt[12] |= (pts >> 7) & 0xFF;
1037 pkt[13] |= (pts << 1) & 0xFE;
1045 if (!m_iframe_search)
1048 unsigned char *data = (unsigned char*)_data; /* remove that const. we know what we are doing. */
1050 // eDebug("filterRecordData, size=%d (mod 188=%d), first byte is %02x", len, len %188, data[0]);
1052 unsigned char *d = data;
1053 while ((d + 3 < data + len) && (d = (unsigned char*)memmem(d, data + len - d, "\x00\x00\x01", 3)))
1055 int offset = d - data;
1056 int ts_offset = offset - offset % 188; /* offset to the start of TS packet */
1057 unsigned char *ts = data + ts_offset;
1058 int pid = ((ts[1] << 8) | ts[2]) & 0x1FFF;
1060 if ((d[3] == 0 || d[3] == 0x09 && d[-1] == 0 && (ts[1] & 0x40)) && (m_pid == pid)) /* picture start */
1062 int picture_type = (d[3]==0 ? (d[5] >> 3) & 7 : (d[4] >> 5) + 1);
1065 // eDebug("%d-frame at %d, offset in TS packet: %d, pid=%04x", picture_type, offset, offset % 188, pid);
1067 if (m_iframe_state == 1)
1069 /* we are allowing data, and stop allowing data on the next frame.
1070 we now found a frame. so stop here. */
1071 memset(data + offset, 0, 188 - (offset%188)); /* zero out rest of TS packet */
1072 current_span_remaining = 0;
1074 unsigned char *fts = ts + 188;
1075 while (fts < (data + len))
1078 fts[2] |= 0xff; /* drop packet */
1082 return len; // ts_offset + 188; /* deliver this packet, but not more. */
1085 if (picture_type != 1) /* we are only interested in I frames */
1088 unsigned char *fts = data;
1092 fts[2] |= 0xff; /* drop packet */
1099 } else if ((d[3] & 0xF0) == 0xE0) /* video stream */
1101 /* verify that this is actually a PES header, not just some ES data */
1102 if (ts[1] & 0x40) /* PUSI set */
1104 int payload_start = 4;
1105 if (ts[3] & 0x20) /* adaptation field present */
1106 payload_start += ts[4] + 1; /* skip AF */
1107 if (payload_start == (offset%188)) /* the 00 00 01 should be directly at the payload start, otherwise it's not a PES header */
1111 eDebug("now locked to pid %04x (%02x %02x %02x %02x)", pid, ts[0], ts[1], ts[2], ts[3]);
1119 d += 4; /* ignore */
1122 if (m_iframe_state == 1)
1125 return 0; /* we need find an iframe first */
1131 DEFINE_REF(eDVBChannel);
1133 eDVBChannel::eDVBChannel(eDVBResourceManager *mgr, eDVBAllocatedFrontend *frontend): m_state(state_idle), m_mgr(mgr)
1135 m_frontend = frontend;
1140 m_skipmode_n = m_skipmode_m = m_skipmode_frames = 0;
1143 m_frontend->get().connectStateChange(slot(*this, &eDVBChannel::frontendStateChanged), m_conn_frontendStateChanged);
1146 eDVBChannel::~eDVBChannel()
1149 m_mgr->removeChannel(this);
1154 void eDVBChannel::frontendStateChanged(iDVBFrontend*fe)
1156 int state, ourstate = 0;
1158 /* if we are already in shutdown, don't change state. */
1159 if (m_state == state_release)
1162 if (fe->getState(state))
1165 if (state == iDVBFrontend::stateLock)
1167 eDebug("OURSTATE: ok");
1168 ourstate = state_ok;
1169 } else if (state == iDVBFrontend::stateTuning)
1171 eDebug("OURSTATE: tuning");
1172 ourstate = state_tuning;
1173 } else if (state == iDVBFrontend::stateLostLock)
1175 /* on managed channels, we try to retune in order to re-acquire lock. */
1176 if (m_current_frontend_parameters)
1178 eDebug("OURSTATE: lost lock, trying to retune");
1179 ourstate = state_tuning;
1180 m_frontend->get().tune(*m_current_frontend_parameters);
1182 /* on unmanaged channels, we don't do this. the client will do this. */
1184 eDebug("OURSTATE: lost lock, unavailable now.");
1185 ourstate = state_unavailable;
1187 } else if (state == iDVBFrontend::stateFailed)
1189 eDebug("OURSTATE: failed");
1190 ourstate = state_failed;
1192 eFatal("state unknown");
1194 if (ourstate != m_state)
1197 m_stateChanged(this);
1201 void eDVBChannel::pvrEvent(int event)
1205 case eFilePushThread::evtEOF:
1206 eDebug("eDVBChannel: End of file!");
1207 m_event(this, evtEOF);
1209 case eFilePushThread::evtUser: /* start */
1211 m_event(this, evtSOF);
1216 void eDVBChannel::cueSheetEvent(int event)
1218 /* we might end up here if playing failed or stopped, but the client hasn't (yet) noted. */
1223 case eCueSheet::evtSeek:
1225 flushPVR(m_cue->m_decoding_demux);
1227 case eCueSheet::evtSkipmode:
1230 m_cue->m_lock.WrLock();
1231 m_cue->m_seek_requests.push_back(std::pair<int, pts_t>(1, 0)); /* resync */
1232 m_cue->m_lock.Unlock();
1233 eRdLocker l(m_cue->m_lock);
1234 if (m_cue->m_skipmode_ratio)
1236 int bitrate = m_tstools.calcBitrate(); /* in bits/s */
1237 eDebug("skipmode ratio is %lld:90000, bitrate is %d bit/s", m_cue->m_skipmode_ratio, bitrate);
1238 /* i agree that this might look a bit like black magic. */
1239 m_skipmode_n = 512*1024; /* must be 1 iframe at least. */
1240 m_skipmode_m = bitrate / 8 / 90000 * m_cue->m_skipmode_ratio / 8;
1241 m_skipmode_frames = m_cue->m_skipmode_ratio / 90000;
1242 m_skipmode_frames_remainder = 0;
1244 if (m_cue->m_skipmode_ratio < 0)
1245 m_skipmode_m -= m_skipmode_n;
1247 eDebug("resolved to: %d %d", m_skipmode_m, m_skipmode_n);
1249 if (abs(m_skipmode_m) < abs(m_skipmode_n))
1251 eWarning("something is wrong with this calculation");
1252 m_skipmode_frames = m_skipmode_n = m_skipmode_m = 0;
1256 eDebug("skipmode ratio is 0, normal play");
1257 m_skipmode_frames = m_skipmode_n = m_skipmode_m = 0;
1260 m_pvr_thread->setIFrameSearch(m_skipmode_n != 0);
1261 if (m_cue->m_skipmode_ratio != 0)
1262 m_pvr_thread->setTimebaseChange(0x10000 * 9000 / (m_cue->m_skipmode_ratio / 10)); /* negative values are also ok */
1264 m_pvr_thread->setTimebaseChange(0); /* normal playback */
1265 eDebug("flush pvr");
1266 flushPVR(m_cue->m_decoding_demux);
1270 case eCueSheet::evtSpanChanged:
1272 m_source_span.clear();
1273 for (std::list<std::pair<pts_t, pts_t> >::const_iterator i(m_cue->m_spans.begin()); i != m_cue->m_spans.end(); ++i)
1275 off_t offset_in, offset_out;
1276 pts_t pts_in = i->first, pts_out = i->second;
1277 if (m_tstools.getOffset(offset_in, pts_in, -1) || m_tstools.getOffset(offset_out, pts_out, 1))
1279 eDebug("span translation failed.\n");
1282 eDebug("source span: %llx .. %llx, translated to %llx..%llx", pts_in, pts_out, offset_in, offset_out);
1283 m_source_span.push_back(std::pair<off_t, off_t>(offset_in, offset_out));
1290 /* align toward zero */
1291 static inline long long align(long long x, int align)
1306 /* align toward zero */
1307 static inline long long align_with_len(long long x, int align, size_t &len)
1323 /* remember, this gets called from another thread. */
1324 void eDVBChannel::getNextSourceSpan(off_t current_offset, size_t bytes_read, off_t &start, size_t &size)
1326 const int blocksize = 188;
1327 unsigned int max = align(10*1024*1024, blocksize);
1328 current_offset = align(current_offset, blocksize);
1332 eDebug("no cue sheet. forcing normal play");
1333 start = current_offset;
1340 eDebug("skipmode %d:%d (x%d)", m_skipmode_m, m_skipmode_n, m_skipmode_frames);
1341 max = align(m_skipmode_n, blocksize);
1344 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 m_cue->m_lock.RdLock();
1391 while (!m_cue->m_seek_requests.empty())
1393 std::pair<int, pts_t> seek = m_cue->m_seek_requests.front();
1394 m_cue->m_lock.Unlock();
1395 m_cue->m_lock.WrLock();
1396 m_cue->m_seek_requests.pop_front();
1397 m_cue->m_lock.Unlock();
1398 m_cue->m_lock.RdLock();
1399 int relative = seek.first;
1400 pts_t pts = seek.second;
1405 if (!m_cue->m_decoder)
1407 eDebug("no decoder - can't seek relative");
1410 if (m_cue->m_decoder->getPTS(0, now))
1412 eDebug("decoder getPTS failed, can't seek relative");
1415 if (!m_cue->m_decoding_demux)
1417 eDebug("getNextSourceSpan, no decoding demux. couldn't seek to %llx... ignore request!", pts);
1418 start = current_offset;
1422 if (getCurrentPosition(m_cue->m_decoding_demux, now, 1))
1424 eDebug("seekTo: getCurrentPosition failed!");
1427 } else if (pts < 0) /* seek relative to end */
1430 if (!getLength(len))
1432 eDebug("seeking relative to end. len=%lld, seek = %lld", len, pts);
1436 eWarning("getLength failed - can't seek relative to end!");
1441 if (relative == 1) /* pts relative */
1452 if (relative == 2) /* AP relative */
1454 eDebug("AP relative seeking: %lld, at %lld", pts, now);
1456 if (m_tstools.getNextAccessPoint(nextap, now, pts))
1458 pts = now - 90000; /* approx. 1s */
1459 eDebug("AP relative seeking failed!");
1463 eDebug("next ap is %llx\n", pts);
1468 if (m_tstools.getOffset(offset, pts, -1))
1470 eDebug("get offset for pts=%lld failed!", pts);
1474 eDebug("ok, resolved skip (rel: %d, diff %lld), now at %08llx", relative, pts, offset);
1475 current_offset = align(offset, blocksize); /* in case tstools return non-aligned offset */
1478 m_cue->m_lock.Unlock();
1480 for (std::list<std::pair<off_t, off_t> >::const_iterator i(m_source_span.begin()); i != m_source_span.end(); ++i)
1482 long long aligned_start = align(i->first, blocksize);
1483 long long aligned_end = align(i->second, blocksize);
1485 if ((current_offset >= aligned_start) && (current_offset < aligned_end))
1487 start = current_offset;
1488 /* max can not exceed max(size_t). aligned_end - current_offset, however, can. */
1489 if ((aligned_end - current_offset) > max)
1492 size = aligned_end - current_offset;
1493 eDebug("HIT, %lld < %lld < %lld, size: %zd", i->first, current_offset, i->second, size);
1496 if (current_offset < aligned_start)
1498 /* ok, our current offset is in an 'out' zone. */
1499 if ((m_skipmode_m >= 0) || (i == m_source_span.begin()))
1501 /* in normal playback, just start at the next zone. */
1504 /* size is not 64bit! */
1505 if ((i->second - i->first) > max)
1508 size = aligned_end - aligned_start;
1511 if (m_skipmode_m < 0)
1513 eDebug("reached SOF");
1516 m_pvr_thread->sendEvent(eFilePushThread::evtUser);
1520 /* when skipping reverse, however, choose the zone before. */
1522 eDebug("skip to previous block, which is %llx..%llx", i->first, i->second);
1525 aligned_start = align(i->first, blocksize);
1526 aligned_end = align(i->second, blocksize);
1528 if ((aligned_end - aligned_start) > max)
1531 len = aligned_end - aligned_start;
1533 start = aligned_end - len;
1534 eDebug("skipping to %llx, %zd", start, len);
1537 eDebug("result: %llx, %zx (%llx %llx)", start, size, aligned_start, aligned_end);
1542 if ((current_offset < -m_skipmode_m) && (m_skipmode_m < 0))
1544 eDebug("reached SOF");
1546 m_pvr_thread->sendEvent(eFilePushThread::evtUser);
1549 if (m_source_span.empty())
1551 start = current_offset;
1553 eDebug("NO CUESHEET. (%08llx, %zd)", start, size);
1556 start = current_offset;
1562 void eDVBChannel::AddUse()
1564 if (++m_use_count > 1 && m_state == state_last_instance)
1567 m_stateChanged(this);
1571 void eDVBChannel::ReleaseUse()
1575 m_state = state_release;
1576 m_stateChanged(this);
1578 else if (m_use_count == 1)
1580 m_state = state_last_instance;
1581 m_stateChanged(this);
1585 RESULT eDVBChannel::setChannel(const eDVBChannelID &channelid, ePtr<iDVBFrontendParameters> &feparm)
1588 m_mgr->removeChannel(this);
1595 eDebug("no frontend to tune!");
1599 m_channel_id = channelid;
1600 m_mgr->addChannel(channelid, this);
1601 m_state = state_tuning;
1602 /* if tuning fails, shutdown the channel immediately. */
1604 res = m_frontend->get().tune(*feparm);
1605 m_current_frontend_parameters = feparm;
1609 m_state = state_release;
1610 m_stateChanged(this);
1617 RESULT eDVBChannel::connectStateChange(const Slot1<void,iDVBChannel*> &stateChange, ePtr<eConnection> &connection)
1619 connection = new eConnection((iDVBChannel*)this, m_stateChanged.connect(stateChange));
1623 RESULT eDVBChannel::connectEvent(const Slot2<void,iDVBChannel*,int> &event, ePtr<eConnection> &connection)
1625 connection = new eConnection((iDVBChannel*)this, m_event.connect(event));
1629 RESULT eDVBChannel::getState(int &state)
1635 RESULT eDVBChannel::setCIRouting(const eDVBCIRouting &routing)
1640 void eDVBChannel::SDTready(int result)
1642 ePyObject args = PyTuple_New(2), ret;
1646 for (std::vector<ServiceDescriptionSection*>::const_iterator i = m_SDT->getSections().begin(); i != m_SDT->getSections().end(); ++i)
1649 PyTuple_SET_ITEM(args, 0, PyInt_FromLong((*i)->getTransportStreamId()));
1650 PyTuple_SET_ITEM(args, 1, PyInt_FromLong((*i)->getOriginalNetworkId()));
1656 PyTuple_SET_ITEM(args, 0, Py_None);
1657 PyTuple_SET_ITEM(args, 1, Py_None);
1661 ret = PyObject_CallObject(m_tsid_onid_callback, args);
1665 Py_DECREF(m_tsid_onid_callback);
1666 m_tsid_onid_callback = ePyObject();
1667 m_tsid_onid_demux = 0;
1671 int eDVBChannel::reserveDemux()
1673 ePtr<iDVBDemux> dmx;
1674 if (!getDemux(dmx, 0))
1677 if (!dmx->getCADemuxID(id))
1683 RESULT eDVBChannel::requestTsidOnid(ePyObject callback)
1685 if (PyCallable_Check(callback))
1687 if (!getDemux(m_tsid_onid_demux, 0))
1689 m_SDT = new eTable<ServiceDescriptionSection>;
1690 CONNECT(m_SDT->tableReady, eDVBChannel::SDTready);
1691 if (m_SDT->start(m_tsid_onid_demux, eDVBSDTSpec()))
1693 m_tsid_onid_demux = 0;
1698 Py_INCREF(callback);
1699 m_tsid_onid_callback = callback;
1707 RESULT eDVBChannel::getDemux(ePtr<iDVBDemux> &demux, int cap)
1709 ePtr<eDVBAllocatedDemux> &our_demux = (cap & capDecode) ? m_decoder_demux : m_demux;
1715 if (m_mgr->allocateDemux(m_frontend ? (eDVBRegisteredFrontend*)*m_frontend : (eDVBRegisteredFrontend*)0, our_demux, cap))
1720 /* don't hold a reference to the decoding demux, we don't need it. */
1722 /* FIXME: by dropping the 'allocated demux' in favour of the 'iDVBDemux',
1723 the refcount is lost. thus, decoding demuxes are never allocated.
1725 this poses a big problem for PiP. */
1727 if (cap & capHoldDecodeReference) // this is set in eDVBResourceManager::allocateDemux for Dm500HD/DM800 and DM8000
1729 else if (cap & capDecode)
1738 RESULT eDVBChannel::getFrontend(ePtr<iDVBFrontend> &frontend)
1743 frontend = &m_frontend->get();
1749 RESULT eDVBChannel::getCurrentFrontendParameters(ePtr<iDVBFrontendParameters> ¶m)
1751 param = m_current_frontend_parameters;
1755 RESULT eDVBChannel::playFile(const char *file)
1757 eRawFile *f = new eRawFile();
1758 ePtr<iTsSource> source = f;
1760 if (f->open(file) < 0)
1762 eDebug("can't open PVR file %s (%m)", file);
1766 return playSource(source, file);
1769 RESULT eDVBChannel::playSource(ePtr<iTsSource> &source, const char *streaminfo_file)
1771 ASSERT(!m_frontend);
1774 m_pvr_thread->stop();
1775 delete m_pvr_thread;
1779 if (!source->valid())
1781 eDebug("PVR source is not valid!");
1785 m_tstools.setSource(source, streaminfo_file);
1787 /* DON'T EVEN THINK ABOUT FIXING THIS. FIX THE ATI SOURCES FIRST,
1788 THEN DO A REAL FIX HERE! */
1790 if (m_pvr_fd_dst < 0)
1792 /* (this codepath needs to be improved anyway.) */
1793 #if HAVE_DVB_API_VERSION < 3
1794 m_pvr_fd_dst = open("/dev/pvr", O_WRONLY);
1796 m_pvr_fd_dst = open("/dev/misc/pvr", O_WRONLY);
1798 if (m_pvr_fd_dst < 0)
1800 eDebug("can't open /dev/misc/pvr - you need to buy the new(!) $$$ box! (%m)"); // or wait for the driver to be improved.
1805 m_pvr_thread = new eDVBChannelFilePush();
1806 m_pvr_thread->enablePVRCommit(1);
1807 m_pvr_thread->setStreamMode(1);
1808 m_pvr_thread->setScatterGather(this);
1810 m_event(this, evtPreStart);
1812 m_pvr_thread->start(source, m_pvr_fd_dst);
1813 CONNECT(m_pvr_thread->m_event, eDVBChannel::pvrEvent);
1816 m_stateChanged(this);
1821 void eDVBChannel::stopSource()
1825 m_pvr_thread->stop();
1826 delete m_pvr_thread;
1829 if (m_pvr_fd_dst >= 0)
1830 ::close(m_pvr_fd_dst);
1832 m_tstools.setSource(d);
1835 void eDVBChannel::stopFile()
1840 void eDVBChannel::setCueSheet(eCueSheet *cuesheet)
1842 m_conn_cueSheetEvent = 0;
1845 m_cue->connectEvent(slot(*this, &eDVBChannel::cueSheetEvent), m_conn_cueSheetEvent);
1848 RESULT eDVBChannel::getLength(pts_t &len)
1850 return m_tstools.calcLen(len);
1853 RESULT eDVBChannel::getCurrentPosition(iDVBDemux *decoding_demux, pts_t &pos, int mode)
1855 if (!decoding_demux)
1862 if (mode == 0) /* demux */
1864 r = decoding_demux->getSTC(now, 0);
1867 eDebug("demux getSTC failed");
1871 now = pos; /* fixup supplied */
1873 off_t off = 0; /* TODO: fixme */
1874 r = m_tstools.fixupPTS(off, now);
1877 eDebug("fixup PTS failed");
1886 void eDVBChannel::flushPVR(iDVBDemux *decoding_demux)
1888 /* when seeking, we have to ensure that all buffers are flushed.
1889 there are basically 3 buffers:
1890 a.) the filepush's internal buffer
1891 b.) the PVR buffer (before demux)
1892 c.) the ratebuffer (after demux)
1894 it's important to clear them in the correct order, otherwise
1895 the ratebuffer (for example) would immediately refill from
1896 the not-yet-flushed PVR buffer.
1899 m_pvr_thread->pause();
1900 /* flush internal filepush buffer */
1901 m_pvr_thread->flush();
1902 /* HACK: flush PVR buffer */
1903 ::ioctl(m_pvr_fd_dst, 0);
1905 /* flush ratebuffers (video, audio) */
1907 decoding_demux->flush();
1909 /* demux will also flush all decoder.. */
1910 /* resume will re-query the SG */
1911 m_pvr_thread->resume();
1914 DEFINE_REF(eCueSheet);
1916 eCueSheet::eCueSheet()
1918 m_skipmode_ratio = 0;
1921 void eCueSheet::seekTo(int relative, const pts_t &pts)
1924 m_seek_requests.push_back(std::pair<int, pts_t>(relative, pts));
1929 void eCueSheet::clear()
1936 void eCueSheet::addSourceSpan(const pts_t &begin, const pts_t &end)
1938 ASSERT(begin < end);
1940 m_spans.push_back(std::pair<pts_t, pts_t>(begin, end));
1944 void eCueSheet::commitSpans()
1946 m_event(evtSpanChanged);
1949 void eCueSheet::setSkipmode(const pts_t &ratio)
1952 m_skipmode_ratio = ratio;
1954 m_event(evtSkipmode);
1957 void eCueSheet::setDecodingDemux(iDVBDemux *demux, iTSMPEGDecoder *decoder)
1959 m_decoding_demux = demux;
1960 m_decoder = decoder;
1963 RESULT eCueSheet::connectEvent(const Slot1<void,int> &event, ePtr<eConnection> &connection)
1965 connection = new eConnection(this, m_event.connect(event));