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))
152 fe = new eDVBFrontend(m_nr, num_fe, ok, true);
154 m_simulate_frontend.push_back(ePtr<eDVBFrontend>(fe));
159 fe = new eDVBFrontend(m_nr, num_fe, ok, false, fe);
161 m_frontend.push_back(ePtr<eDVBFrontend>(fe));
172 #if HAVE_DVB_API_VERSION < 3
173 sprintf(filename, "/dev/dvb/card%d/demux%d", m_nr, num_demux);
175 sprintf(filename, "/dev/dvb/adapter%d/demux%d", m_nr, num_demux);
177 if (stat(filename, &s))
179 ePtr<eDVBDemux> demux;
181 demux = new eDVBDemux(m_nr, num_demux);
182 m_demux.push_back(demux);
188 int eDVBAdapterLinux::getNumDemux()
190 return m_demux.size();
193 RESULT eDVBAdapterLinux::getDemux(ePtr<eDVBDemux> &demux, int nr)
195 eSmartPtrList<eDVBDemux>::iterator i(m_demux.begin());
196 while (nr && (i != m_demux.end()))
202 if (i != m_demux.end())
210 int eDVBAdapterLinux::getNumFrontends()
212 return m_frontend.size();
215 RESULT eDVBAdapterLinux::getFrontend(ePtr<eDVBFrontend> &fe, int nr, bool simulate)
217 eSmartPtrList<eDVBFrontend>::iterator i(simulate ? m_simulate_frontend.begin() : m_frontend.begin());
218 while (nr && (i != m_frontend.end()))
224 if (i != m_frontend.end())
232 int eDVBAdapterLinux::exist(int nr)
236 #if HAVE_DVB_API_VERSION < 3
237 sprintf(filename, "/dev/dvb/card%d", nr);
239 sprintf(filename, "/dev/dvb/adapter%d", nr);
241 if (!stat(filename, &s))
246 eDVBResourceManager::~eDVBResourceManager()
248 if (instance == this)
252 void eDVBResourceManager::addAdapter(iDVBAdapter *adapter)
254 int num_fe = adapter->getNumFrontends();
255 int num_demux = adapter->getNumDemux();
257 m_adapter.push_back(adapter);
260 for (i=0; i<num_demux; ++i)
262 ePtr<eDVBDemux> demux;
263 if (!adapter->getDemux(demux, i))
264 m_demux.push_back(new eDVBRegisteredDemux(demux, adapter));
267 ePtr<eDVBRegisteredFrontend> prev_dvbt_frontend;
268 for (i=0; i<num_fe; ++i)
270 ePtr<eDVBFrontend> frontend;
271 if (!adapter->getFrontend(frontend, i))
274 frontend->getFrontendType(frontendType);
275 eDVBRegisteredFrontend *new_fe = new eDVBRegisteredFrontend(frontend, adapter);
276 CONNECT(new_fe->stateChanged, eDVBResourceManager::feStateChanged);
277 m_frontend.push_back(new_fe);
278 frontend->setSEC(m_sec);
279 // we must link all dvb-t frontends ( for active antenna voltage )
280 if (frontendType == iDVBFrontend::feTerrestrial)
282 if (prev_dvbt_frontend)
284 prev_dvbt_frontend->m_frontend->setData(eDVBFrontend::LINKED_NEXT_PTR, (long)new_fe);
285 frontend->setData(eDVBFrontend::LINKED_PREV_PTR, (long)&(*prev_dvbt_frontend));
287 prev_dvbt_frontend = new_fe;
292 prev_dvbt_frontend = 0;
293 for (i=0; i<num_fe; ++i)
295 ePtr<eDVBFrontend> frontend;
296 if (!adapter->getFrontend(frontend, i, true))
299 frontend->getFrontendType(frontendType);
300 eDVBRegisteredFrontend *new_fe = new eDVBRegisteredFrontend(frontend, adapter);
301 // CONNECT(new_fe->stateChanged, eDVBResourceManager::feStateChanged);
302 m_simulate_frontend.push_back(new_fe);
303 frontend->setSEC(m_sec);
304 // we must link all dvb-t frontends ( for active antenna voltage )
305 if (frontendType == iDVBFrontend::feTerrestrial)
307 if (prev_dvbt_frontend)
309 prev_dvbt_frontend->m_frontend->setData(eDVBFrontend::LINKED_NEXT_PTR, (long)new_fe);
310 frontend->setData(eDVBFrontend::LINKED_PREV_PTR, (long)&(*prev_dvbt_frontend));
312 prev_dvbt_frontend = new_fe;
319 PyObject *eDVBResourceManager::setFrontendSlotInformations(ePyObject list)
321 if (!PyList_Check(list))
323 PyErr_SetString(PyExc_StandardError, "eDVBResourceManager::setFrontendSlotInformations argument should be a python list");
326 unsigned int assigned=0;
327 for (eSmartPtrList<eDVBRegisteredFrontend>::iterator i(m_frontend.begin()); i != m_frontend.end(); ++i)
330 while (pos < PyList_Size(list)) {
331 ePyObject obj = PyList_GET_ITEM(list, pos++);
332 if (!i->m_frontend->setSlotInfo(obj))
338 if (assigned != m_frontend.size()) {
340 sprintf(blasel, "eDVBResourceManager::setFrontendSlotInformations .. assigned %zd socket informations, but %d registered frontends!",
341 m_frontend.size(), assigned);
342 PyErr_SetString(PyExc_StandardError, blasel);
345 for (eSmartPtrList<eDVBRegisteredFrontend>::iterator i(m_simulate_frontend.begin()); i != m_simulate_frontend.end(); ++i)
348 while (pos < PyList_Size(list)) {
349 ePyObject obj = PyList_GET_ITEM(list, pos++);
350 if (!i->m_frontend->setSlotInfo(obj))
358 RESULT eDVBResourceManager::allocateFrontend(ePtr<eDVBAllocatedFrontend> &fe, ePtr<iDVBFrontendParameters> &feparm, bool simulate)
360 eSmartPtrList<eDVBRegisteredFrontend> &frontends = simulate ? m_simulate_frontend : m_frontend;
361 ePtr<eDVBRegisteredFrontend> best;
365 for (eSmartPtrList<eDVBRegisteredFrontend>::iterator i(frontends.begin()); i != frontends.end(); ++i)
367 int c = i->m_frontend->isCompatibleWith(feparm);
369 if (c) /* if we have at least one frontend which is compatible with the source, flag this. */
374 // eDebug("Slot %d, score %d", i->m_frontend->getSlotID(), c);
382 // eDebug("Slot %d, score %d... but BUSY!!!!!!!!!!!", i->m_frontend->getSlotID(), c);
387 fe = new eDVBAllocatedFrontend(best);
394 return errAllSourcesBusy;
396 return errNoSourceFound;
399 RESULT eDVBResourceManager::allocateFrontendByIndex(ePtr<eDVBAllocatedFrontend> &fe, int slot_index)
401 int err = errNoSourceFound;
402 for (eSmartPtrList<eDVBRegisteredFrontend>::iterator i(m_frontend.begin()); i != m_frontend.end(); ++i)
403 if (!i->m_inuse && i->m_frontend->getSlotID() == slot_index)
405 // check if another slot linked to this is in use
407 i->m_frontend->getData(eDVBFrontend::SATPOS_DEPENDS_PTR, tmp);
410 eDVBRegisteredFrontend *satpos_depends_to_fe = (eDVBRegisteredFrontend *)tmp;
411 if (satpos_depends_to_fe->m_inuse)
413 eDebug("another satpos depending frontend is in use.. so allocateFrontendByIndex not possible!");
414 err = errAllSourcesBusy;
415 goto alloc_fe_by_id_not_possible;
418 else // check linked tuners
420 i->m_frontend->getData(eDVBFrontend::LINKED_NEXT_PTR, tmp);
423 eDVBRegisteredFrontend *next = (eDVBRegisteredFrontend *) tmp;
426 eDebug("another linked frontend is in use.. so allocateFrontendByIndex not possible!");
427 err = errAllSourcesBusy;
428 goto alloc_fe_by_id_not_possible;
430 next->m_frontend->getData(eDVBFrontend::LINKED_NEXT_PTR, tmp);
432 i->m_frontend->getData(eDVBFrontend::LINKED_PREV_PTR, tmp);
435 eDVBRegisteredFrontend *prev = (eDVBRegisteredFrontend *) tmp;
438 eDebug("another linked frontend is in use.. so allocateFrontendByIndex not possible!");
439 err = errAllSourcesBusy;
440 goto alloc_fe_by_id_not_possible;
442 prev->m_frontend->getData(eDVBFrontend::LINKED_PREV_PTR, tmp);
445 fe = new eDVBAllocatedFrontend(i);
448 alloc_fe_by_id_not_possible:
453 #define capHoldDecodeReference 64
455 RESULT eDVBResourceManager::allocateDemux(eDVBRegisteredFrontend *fe, ePtr<eDVBAllocatedDemux> &demux, int &cap)
457 /* find first unused demux which is on same adapter as frontend (or any, if PVR)
458 never use the first one unless we need a decoding demux. */
460 eDebug("allocate demux");
461 eSmartPtrList<eDVBRegisteredDemux>::iterator i(m_demux.begin());
465 if (i == m_demux.end())
468 ePtr<eDVBRegisteredDemux> unused;
470 if (m_boxtype == DM800) // dm800
472 cap |= capHoldDecodeReference; // this is checked in eDVBChannel::getDemux
473 for (; i != m_demux.end(); ++i, ++n)
484 if (i->m_adapter == fe->m_adapter &&
485 i->m_demux->getSource() == fe->m_frontend->getDVBID())
487 demux = new eDVBAllocatedDemux(i);
491 else if (i->m_demux->getSource() == -1) // PVR
493 demux = new eDVBAllocatedDemux(i);
499 else if (m_boxtype == DM7025) // ATI
501 /* FIXME: hardware demux policy */
502 if (!(cap & iDVBChannel::capDecode))
504 if (m_demux.size() > 2) /* assumed to be true, otherwise we have lost anyway */
511 for (; i != m_demux.end(); ++i, ++n)
513 int is_decode = n < 2;
515 int in_use = is_decode ? (i->m_demux->getRefCount() != 2) : i->m_inuse;
517 if ((!in_use) && ((!fe) || (i->m_adapter == fe->m_adapter)))
519 if ((cap & iDVBChannel::capDecode) && !is_decode)
526 else if (m_boxtype == DM8000 || m_boxtype == DM500HD || m_boxtype == DM800SE || m_boxtype == DM7020HD)
528 iDVBAdapter *adapter = fe ? fe->m_adapter : m_adapter.begin(); /* look for a demux on the same adapter as the frontend, or the first adapter for dvr playback */
529 int source = fe ? fe->m_frontend->getDVBID() : -1;
530 cap |= capHoldDecodeReference; // this is checked in eDVBChannel::getDemux
534 * For pvr playback, start with the last demux.
535 * On some hardware, we have less ca devices than demuxes,
536 * so we should try to leave the first demuxes for live tv,
537 * and start with the last for pvr playback
542 while (i != m_demux.end())
544 if (i->m_adapter == adapter)
548 /* mark the first unused demux, we'll use that when we do not find a better match */
549 if (!unused) unused = i;
553 /* demux is in use, see if we can share it */
554 if (source >= 0 && i->m_demux->getSource() == source)
556 demux = new eDVBAllocatedDemux(i);
574 demux = new eDVBAllocatedDemux(unused);
576 demux->get().setSourceFrontend(fe->m_frontend->getDVBID());
578 demux->get().setSourcePVR(0);
582 eDebug("demux not found");
586 RESULT eDVBResourceManager::setChannelList(iDVBChannelList *list)
592 RESULT eDVBResourceManager::getChannelList(ePtr<iDVBChannelList> &list)
601 #define eDebugNoSimulate(x...) \
608 // eDebugNoNewLine("SIMULATE:"); \
613 RESULT eDVBResourceManager::allocateChannel(const eDVBChannelID &channelid, eUsePtr<iDVBChannel> &channel, bool simulate)
615 /* first, check if a channel is already existing. */
616 std::list<active_channel> &active_channels = simulate ? m_active_simulate_channels : m_active_channels;
618 if (!simulate && m_cached_channel)
620 eDVBChannel *cache_chan = (eDVBChannel*)&(*m_cached_channel);
621 if(channelid==cache_chan->getChannelID())
623 eDebug("use cached_channel");
624 channel = m_cached_channel;
627 m_cached_channel_state_changed_conn.disconnect();
629 m_releaseCachedChannelTimer->stop();
632 eDebugNoSimulate("allocate channel.. %04x:%04x", channelid.transport_stream_id.get(), channelid.original_network_id.get());
633 for (std::list<active_channel>::iterator i(active_channels.begin()); i != active_channels.end(); ++i)
635 eDebugNoSimulate("available channel.. %04x:%04x", i->m_channel_id.transport_stream_id.get(), i->m_channel_id.original_network_id.get());
636 if (i->m_channel_id == channelid)
638 eDebugNoSimulate("found shared channel..");
639 channel = i->m_channel;
644 /* no currently available channel is tuned to this channelid. create a new one, if possible. */
648 eDebugNoSimulate("no channel list set!");
649 return errNoChannelList;
652 ePtr<iDVBFrontendParameters> feparm;
653 if (m_list->getChannelFrontendData(channelid, feparm))
655 eDebugNoSimulate("channel not found!");
656 return errChannelNotInList;
659 /* allocate a frontend. */
661 ePtr<eDVBAllocatedFrontend> fe;
663 int err = allocateFrontend(fe, feparm, simulate);
668 ePtr<eDVBChannel> ch = new eDVBChannel(this, fe);
670 res = ch->setChannel(channelid, feparm);
674 return errChidNotFound;
681 m_cached_channel = channel = ch;
682 m_cached_channel_state_changed_conn =
683 CONNECT(ch->m_stateChanged,eDVBResourceManager::DVBChannelStateChanged);
689 void eDVBResourceManager::DVBChannelStateChanged(iDVBChannel *chan)
692 chan->getState(state);
695 case iDVBChannel::state_release:
696 case iDVBChannel::state_ok:
698 eDebug("stop release channel timer");
699 m_releaseCachedChannelTimer->stop();
702 case iDVBChannel::state_last_instance:
704 eDebug("start release channel timer");
705 m_releaseCachedChannelTimer->start(3000, true);
708 default: // ignore all other events
713 void eDVBResourceManager::releaseCachedChannel()
715 eDebug("release cached channel (timer timeout)");
719 RESULT eDVBResourceManager::allocateRawChannel(eUsePtr<iDVBChannel> &channel, int slot_index)
721 ePtr<eDVBAllocatedFrontend> fe;
723 if (m_cached_channel)
725 m_cached_channel_state_changed_conn.disconnect();
727 m_releaseCachedChannelTimer->stop();
730 int err = allocateFrontendByIndex(fe, slot_index);
734 channel = new eDVBChannel(this, fe);
738 RESULT eDVBResourceManager::allocatePVRChannel(const eDVBChannelID &channelid, eUsePtr<iDVBPVRChannel> &channel)
740 ePtr<eDVBAllocatedDemux> demux;
742 if (m_cached_channel && m_releaseCachedChannelTimer->isActive())
744 m_cached_channel_state_changed_conn.disconnect();
746 m_releaseCachedChannelTimer->stop();
749 ePtr<eDVBChannel> ch = new eDVBChannel(this, 0);
753 * user provided a channelid, with the clear intention for
754 * this channel to be registered at the resource manager.
755 * (allowing e.g. epgcache to be started)
757 ePtr<iDVBFrontendParameters> feparm;
758 ch->setChannel(channelid, feparm);
764 RESULT eDVBResourceManager::addChannel(const eDVBChannelID &chid, eDVBChannel *ch)
766 ePtr<iDVBFrontend> fe;
767 if (!ch->getFrontend(fe))
769 eDVBFrontend *frontend = (eDVBFrontend*)&(*fe);
770 if (frontend->is_simulate())
771 m_active_simulate_channels.push_back(active_channel(chid, ch));
774 m_active_channels.push_back(active_channel(chid, ch));
775 /* emit */ m_channelAdded(ch);
781 RESULT eDVBResourceManager::removeChannel(eDVBChannel *ch)
783 ePtr<iDVBFrontend> fe;
784 if (!ch->getFrontend(fe))
786 eDVBFrontend *frontend = (eDVBFrontend*)&(*fe);
787 std::list<active_channel> &active_channels = frontend->is_simulate() ? m_active_simulate_channels : m_active_channels;
789 for (std::list<active_channel>::iterator i(active_channels.begin()); i != active_channels.end();)
791 if (i->m_channel == ch)
793 i = active_channels.erase(i);
805 RESULT eDVBResourceManager::connectChannelAdded(const Slot1<void,eDVBChannel*> &channelAdded, ePtr<eConnection> &connection)
807 connection = new eConnection((eDVBResourceManager*)this, m_channelAdded.connect(channelAdded));
811 int eDVBResourceManager::canAllocateFrontend(ePtr<iDVBFrontendParameters> &feparm, bool simulate)
813 eSmartPtrList<eDVBRegisteredFrontend> &frontends = simulate ? m_simulate_frontend : m_frontend;
814 ePtr<eDVBRegisteredFrontend> best;
817 for (eSmartPtrList<eDVBRegisteredFrontend>::iterator i(frontends.begin()); i != frontends.end(); ++i)
820 int c = i->m_frontend->isCompatibleWith(feparm);
827 int tuner_type_channel_default(ePtr<iDVBChannelList> &channellist, const eDVBChannelID &chid)
831 ePtr<iDVBFrontendParameters> feparm;
832 if (!channellist->getChannelFrontendData(chid, feparm))
835 if (!feparm->getSystem(system))
839 case iDVBFrontend::feSatellite:
841 case iDVBFrontend::feCable:
843 case iDVBFrontend::feTerrestrial:
854 int eDVBResourceManager::canAllocateChannel(const eDVBChannelID &channelid, const eDVBChannelID& ignore, bool simulate)
856 std::list<active_channel> &active_channels = simulate ? m_active_simulate_channels : m_active_channels;
858 if (!simulate && m_cached_channel)
860 eDVBChannel *cache_chan = (eDVBChannel*)&(*m_cached_channel);
861 if(channelid==cache_chan->getChannelID())
862 return tuner_type_channel_default(m_list, channelid);
865 /* first, check if a channel is already existing. */
866 // eDebug("allocate channel.. %04x:%04x", channelid.transport_stream_id.get(), channelid.original_network_id.get());
867 for (std::list<active_channel>::iterator i(active_channels.begin()); i != active_channels.end(); ++i)
869 // eDebug("available channel.. %04x:%04x", i->m_channel_id.transport_stream_id.get(), i->m_channel_id.original_network_id.get());
870 if (i->m_channel_id == channelid)
872 // eDebug("found shared channel..");
873 return tuner_type_channel_default(m_list, channelid);
877 int *decremented_cached_channel_fe_usecount=NULL,
878 *decremented_fe_usecount=NULL;
880 for (std::list<active_channel>::iterator i(active_channels.begin()); i != active_channels.end(); ++i)
882 eSmartPtrList<eDVBRegisteredFrontend> &frontends = simulate ? m_simulate_frontend : m_frontend;
883 // eDebug("available channel.. %04x:%04x", i->m_channel_id.transport_stream_id.get(), i->m_channel_id.original_network_id.get());
884 if (i->m_channel_id == ignore)
886 eDVBChannel *channel = (eDVBChannel*) &(*i->m_channel);
887 // one eUsePtr<iDVBChannel> is used in eDVBServicePMTHandler
888 // another on eUsePtr<iDVBChannel> is used in the eDVBScan instance used in eDVBServicePMTHandler (for SDT scan)
889 // so we must check here if usecount is 3 (when the channel is equal to the cached channel)
890 // or 2 when the cached channel is not equal to the compared channel
891 if (channel == &(*m_cached_channel) ? channel->getUseCount() == 3 : channel->getUseCount() == 2) // channel only used once..
893 ePtr<iDVBFrontend> fe;
894 if (!i->m_channel->getFrontend(fe))
896 for (eSmartPtrList<eDVBRegisteredFrontend>::iterator ii(frontends.begin()); ii != frontends.end(); ++ii)
898 if ( &(*fe) == &(*ii->m_frontend) )
901 decremented_fe_usecount = &ii->m_inuse;
902 if (channel == &(*m_cached_channel))
903 decremented_cached_channel_fe_usecount = decremented_fe_usecount;
913 if (!decremented_cached_channel_fe_usecount)
915 if (m_cached_channel)
917 eDVBChannel *channel = (eDVBChannel*) &(*m_cached_channel);
918 if (channel->getUseCount() == 1)
920 ePtr<iDVBFrontend> fe;
921 if (!channel->getFrontend(fe))
923 eSmartPtrList<eDVBRegisteredFrontend> &frontends = simulate ? m_simulate_frontend : m_frontend;
924 for (eSmartPtrList<eDVBRegisteredFrontend>::iterator ii(frontends.begin()); ii != frontends.end(); ++ii)
926 if ( &(*fe) == &(*ii->m_frontend) )
929 decremented_cached_channel_fe_usecount = &ii->m_inuse;
938 decremented_cached_channel_fe_usecount=NULL;
940 ePtr<iDVBFrontendParameters> feparm;
944 eDebug("no channel list set!");
948 if (m_list->getChannelFrontendData(channelid, feparm))
950 eDebug("channel not found!");
954 ret = canAllocateFrontend(feparm, simulate);
957 if (decremented_fe_usecount)
958 ++(*decremented_fe_usecount);
959 if (decremented_cached_channel_fe_usecount)
960 ++(*decremented_cached_channel_fe_usecount);
965 bool eDVBResourceManager::canMeasureFrontendInputPower()
967 for (eSmartPtrList<eDVBRegisteredFrontend>::iterator i(m_frontend.begin()); i != m_frontend.end(); ++i)
969 return i->m_frontend->readInputpower() >= 0;
974 class eDVBChannelFilePush: public eFilePushThread
977 eDVBChannelFilePush() { setIFrameSearch(0); setTimebaseChange(0); }
978 void setIFrameSearch(int enabled) { m_iframe_search = enabled; m_iframe_state = 0; }
980 /* "timebase change" is for doing trickmode playback at an exact speed, even when pictures are skipped. */
981 /* you need to set it to 1/16 if you want 16x playback, for example. you need video master sync. */
982 void setTimebaseChange(int ratio) { m_timebase_change = ratio; } /* 16bit fixpoint, 0 for disable */
984 int m_iframe_search, m_iframe_state, m_pid;
985 int m_timebase_change;
986 int filterRecordData(const unsigned char *data, int len, size_t ¤t_span_remaining);
989 int eDVBChannelFilePush::filterRecordData(const unsigned char *_data, int len, size_t ¤t_span_remaining)
992 if (m_timebase_change)
994 eDebug("timebase change: %d", m_timebase_change);
996 for (offset = 0; offset < len; offset += 188)
998 unsigned char *pkt = (unsigned char*)_data + offset;
999 if (pkt[1] & 0x40) /* pusi */
1001 if (pkt[3] & 0x20) // adaption field present?
1002 pkt += pkt[4] + 4 + 1; /* skip adaption field and header */
1004 pkt += 4; /* skip header */
1005 if (pkt[0] || pkt[1] || (pkt[2] != 1))
1007 eWarning("broken startcode");
1013 if (pkt[7] & 0x80) // PTS present?
1015 pts = ((unsigned long long)(pkt[ 9]&0xE)) << 29;
1016 pts |= ((unsigned long long)(pkt[10]&0xFF)) << 22;
1017 pts |= ((unsigned long long)(pkt[11]&0xFE)) << 14;
1018 pts |= ((unsigned long long)(pkt[12]&0xFF)) << 7;
1019 pts |= ((unsigned long long)(pkt[13]&0xFE)) >> 1;
1023 RESULT r = m_tstools.fixupPTS(off, pts);
1025 eWarning("fixup PTS while trickmode playback failed.\n");
1028 int sec = pts / 90000;
1029 int frm = pts % 90000;
1037 // eDebug("original, fixed pts: %016llx %d:%02d:%02d:%02d:%05d", pts, d, hr, min, sec, frm);
1039 pts += 0x80000000LL;
1040 pts *= m_timebase_change;
1052 // eDebug("new pts (after timebase change): %016llx %d:%02d:%02d:%02d:%05d", pts, d, hr, min, sec, frm);
1060 pkt[9] |= (pts >> 29) & 0xE;
1061 pkt[10] |= (pts >> 22) & 0xFF;
1062 pkt[11] |= (pts >> 14) & 0xFE;
1063 pkt[12] |= (pts >> 7) & 0xFF;
1064 pkt[13] |= (pts << 1) & 0xFE;
1072 if (!m_iframe_search)
1075 unsigned char *data = (unsigned char*)_data; /* remove that const. we know what we are doing. */
1077 // eDebug("filterRecordData, size=%d (mod 188=%d), first byte is %02x", len, len %188, data[0]);
1079 unsigned char *d = data;
1080 while ((d + 3 < data + len) && (d = (unsigned char*)memmem(d, data + len - d, "\x00\x00\x01", 3)))
1082 int offset = d - data;
1083 int ts_offset = offset - offset % 188; /* offset to the start of TS packet */
1084 unsigned char *ts = data + ts_offset;
1085 int pid = ((ts[1] << 8) | ts[2]) & 0x1FFF;
1087 if ((d[3] == 0 || d[3] == 0x09 && d[-1] == 0 && (ts[1] & 0x40)) && (m_pid == pid)) /* picture start */
1089 int picture_type = (d[3]==0 ? (d[5] >> 3) & 7 : (d[4] >> 5) + 1);
1092 // eDebug("%d-frame at %d, offset in TS packet: %d, pid=%04x", picture_type, offset, offset % 188, pid);
1094 if (m_iframe_state == 1)
1096 /* we are allowing data, and stop allowing data on the next frame.
1097 we now found a frame. so stop here. */
1098 memset(data + offset, 0, 188 - (offset%188)); /* zero out rest of TS packet */
1099 current_span_remaining = 0;
1101 unsigned char *fts = ts + 188;
1102 while (fts < (data + len))
1105 fts[2] |= 0xff; /* drop packet */
1109 return len; // ts_offset + 188; /* deliver this packet, but not more. */
1112 if (picture_type != 1) /* we are only interested in I frames */
1115 unsigned char *fts = data;
1119 fts[2] |= 0xff; /* drop packet */
1126 } else if ((d[3] & 0xF0) == 0xE0) /* video stream */
1128 /* verify that this is actually a PES header, not just some ES data */
1129 if (ts[1] & 0x40) /* PUSI set */
1131 int payload_start = 4;
1132 if (ts[3] & 0x20) /* adaptation field present */
1133 payload_start += ts[4] + 1; /* skip AF */
1134 if (payload_start == (offset%188)) /* the 00 00 01 should be directly at the payload start, otherwise it's not a PES header */
1138 eDebug("now locked to pid %04x (%02x %02x %02x %02x)", pid, ts[0], ts[1], ts[2], ts[3]);
1146 d += 4; /* ignore */
1149 if (m_iframe_state == 1)
1152 return 0; /* we need find an iframe first */
1158 DEFINE_REF(eDVBChannel);
1160 eDVBChannel::eDVBChannel(eDVBResourceManager *mgr, eDVBAllocatedFrontend *frontend): m_state(state_idle), m_mgr(mgr)
1162 m_frontend = frontend;
1167 m_skipmode_n = m_skipmode_m = m_skipmode_frames = 0;
1170 m_frontend->get().connectStateChange(slot(*this, &eDVBChannel::frontendStateChanged), m_conn_frontendStateChanged);
1173 eDVBChannel::~eDVBChannel()
1176 m_mgr->removeChannel(this);
1181 void eDVBChannel::frontendStateChanged(iDVBFrontend*fe)
1183 int state, ourstate = 0;
1185 /* if we are already in shutdown, don't change state. */
1186 if (m_state == state_release)
1189 if (fe->getState(state))
1192 if (state == iDVBFrontend::stateLock)
1194 eDebug("OURSTATE: ok");
1195 ourstate = state_ok;
1196 } else if (state == iDVBFrontend::stateTuning)
1198 eDebug("OURSTATE: tuning");
1199 ourstate = state_tuning;
1200 } else if (state == iDVBFrontend::stateLostLock)
1202 /* on managed channels, we try to retune in order to re-acquire lock. */
1203 if (m_current_frontend_parameters)
1205 eDebug("OURSTATE: lost lock, trying to retune");
1206 ourstate = state_tuning;
1207 m_frontend->get().tune(*m_current_frontend_parameters);
1209 /* on unmanaged channels, we don't do this. the client will do this. */
1211 eDebug("OURSTATE: lost lock, unavailable now.");
1212 ourstate = state_unavailable;
1214 } else if (state == iDVBFrontend::stateFailed)
1216 #ifdef BUILD_VUPLUS /* ikseong */
1217 if (m_current_frontend_parameters)
1219 eDebug("OURSTATE: lost lock, trying to retune");
1220 ourstate = state_tuning;
1221 m_frontend->get().tune(*m_current_frontend_parameters);
1225 eDebug("OURSTATE: failed");
1226 ourstate = state_failed;
1229 eDebug("OURSTATE: failed");
1230 ourstate = state_failed;
1233 eFatal("state unknown");
1235 if (ourstate != m_state)
1238 m_stateChanged(this);
1242 void eDVBChannel::pvrEvent(int event)
1246 case eFilePushThread::evtEOF:
1247 eDebug("eDVBChannel: End of file!");
1248 m_event(this, evtEOF);
1250 case eFilePushThread::evtUser: /* start */
1252 m_event(this, evtSOF);
1257 void eDVBChannel::cueSheetEvent(int event)
1259 /* we might end up here if playing failed or stopped, but the client hasn't (yet) noted. */
1264 case eCueSheet::evtSeek:
1266 flushPVR(m_cue->m_decoding_demux);
1268 case eCueSheet::evtSkipmode:
1271 m_cue->m_lock.WrLock();
1272 m_cue->m_seek_requests.push_back(std::pair<int, pts_t>(1, 0)); /* resync */
1273 m_cue->m_lock.Unlock();
1274 eRdLocker l(m_cue->m_lock);
1275 if (m_cue->m_skipmode_ratio)
1277 int bitrate = m_tstools.calcBitrate(); /* in bits/s */
1278 eDebug("skipmode ratio is %lld:90000, bitrate is %d bit/s", m_cue->m_skipmode_ratio, bitrate);
1279 /* i agree that this might look a bit like black magic. */
1280 m_skipmode_n = 512*1024; /* must be 1 iframe at least. */
1281 m_skipmode_m = bitrate / 8 / 90000 * m_cue->m_skipmode_ratio / 8;
1282 m_skipmode_frames = m_cue->m_skipmode_ratio / 90000;
1283 m_skipmode_frames_remainder = 0;
1285 if (m_cue->m_skipmode_ratio < 0)
1286 m_skipmode_m -= m_skipmode_n;
1288 eDebug("resolved to: %d %d", m_skipmode_m, m_skipmode_n);
1290 if (abs(m_skipmode_m) < abs(m_skipmode_n))
1292 eWarning("something is wrong with this calculation");
1293 m_skipmode_frames = m_skipmode_n = m_skipmode_m = 0;
1297 eDebug("skipmode ratio is 0, normal play");
1298 m_skipmode_frames = m_skipmode_n = m_skipmode_m = 0;
1301 m_pvr_thread->setIFrameSearch(m_skipmode_n != 0);
1302 if (m_cue->m_skipmode_ratio != 0)
1303 m_pvr_thread->setTimebaseChange(0x10000 * 9000 / (m_cue->m_skipmode_ratio / 10)); /* negative values are also ok */
1305 m_pvr_thread->setTimebaseChange(0); /* normal playback */
1306 eDebug("flush pvr");
1307 flushPVR(m_cue->m_decoding_demux);
1311 case eCueSheet::evtSpanChanged:
1313 m_source_span.clear();
1314 for (std::list<std::pair<pts_t, pts_t> >::const_iterator i(m_cue->m_spans.begin()); i != m_cue->m_spans.end(); ++i)
1316 off_t offset_in, offset_out;
1317 pts_t pts_in = i->first, pts_out = i->second;
1318 if (m_tstools.getOffset(offset_in, pts_in, -1) || m_tstools.getOffset(offset_out, pts_out, 1))
1320 eDebug("span translation failed.\n");
1323 eDebug("source span: %llx .. %llx, translated to %llx..%llx", pts_in, pts_out, offset_in, offset_out);
1324 m_source_span.push_back(std::pair<off_t, off_t>(offset_in, offset_out));
1331 /* align toward zero */
1332 static inline long long align(long long x, int align)
1347 /* align toward zero */
1348 static inline long long align_with_len(long long x, int align, size_t &len)
1365 /* remember, this gets called from another thread. */
1366 void eDVBChannel::getNextSourceSpan(off_t current_offset, size_t bytes_read, off_t &start, size_t &size)
1368 const int blocksize = 188;
1369 unsigned int max = align(10*1024*1024, blocksize);
1370 current_offset = align(current_offset, blocksize);
1374 eDebug("no cue sheet. forcing normal play");
1375 start = current_offset;
1382 eDebug("skipmode %d:%d (x%d)", m_skipmode_m, m_skipmode_n, m_skipmode_frames);
1383 max = align(m_skipmode_n, blocksize);
1386 eDebug("getNextSourceSpan, current offset is %08lld, m_skipmode_m = %d!", current_offset, m_skipmode_m);
1387 int frame_skip_success = 0;
1391 int frames_to_skip = m_skipmode_frames + m_skipmode_frames_remainder;
1392 eDebug("we are at %lld, and we try to skip %d+%d frames from here", current_offset, m_skipmode_frames, m_skipmode_frames_remainder);
1394 off_t iframe_start = current_offset;
1395 int frames_skipped = frames_to_skip;
1396 if (!m_tstools.findNextPicture(iframe_start, iframe_len, frames_skipped))
1398 m_skipmode_frames_remainder = frames_to_skip - frames_skipped;
1399 eDebug("successfully skipped %d (out of %d, rem now %d) frames.", frames_skipped, frames_to_skip, m_skipmode_frames_remainder);
1400 current_offset = align_with_len(iframe_start, blocksize, iframe_len);
1401 max = align(iframe_len + 187, blocksize);
1402 frame_skip_success = 1;
1405 m_skipmode_frames_remainder = 0;
1406 eDebug("frame skipping failed, reverting to byte-skipping");
1410 if (!frame_skip_success)
1412 current_offset += align(m_skipmode_m, blocksize);
1413 if(current_offset < 0)
1419 eDebug("we are at %lld, and we try to find the iframe here:", current_offset);
1421 off_t start_offset = current_offset;
1422 off_t new_offset = start_offset;
1423 int direction = (m_skipmode_m < 0) ? -1 : +1;
1424 if (m_tstools.findFrame(start_offset, new_offset, iframe_len, direction))
1428 current_offset = align_with_len(new_offset, blocksize, iframe_len);
1429 max = align(iframe_len, blocksize);
1435 m_cue->m_lock.RdLock();
1437 while (!m_cue->m_seek_requests.empty())
1439 std::pair<int, pts_t> seek = m_cue->m_seek_requests.front();
1440 m_cue->m_lock.Unlock();
1441 m_cue->m_lock.WrLock();
1442 m_cue->m_seek_requests.pop_front();
1443 m_cue->m_lock.Unlock();
1444 m_cue->m_lock.RdLock();
1445 int relative = seek.first;
1446 pts_t pts = seek.second;
1451 if (!m_cue->m_decoder)
1453 eDebug("no decoder - can't seek relative");
1456 if (m_cue->m_decoder->getPTS(0, now))
1458 eDebug("decoder getPTS failed, can't seek relative");
1461 if (!m_cue->m_decoding_demux)
1463 eDebug("getNextSourceSpan, no decoding demux. couldn't seek to %llx... ignore request!", pts);
1464 start = current_offset;
1468 if (getCurrentPosition(m_cue->m_decoding_demux, now, 1))
1470 eDebug("seekTo: getCurrentPosition failed!");
1473 } else if (pts < 0) /* seek relative to end */
1476 if (!getLength(len))
1478 eDebug("seeking relative to end. len=%lld, seek = %lld", len, pts);
1482 eWarning("getLength failed - can't seek relative to end!");
1487 if (relative == 1) /* pts relative */
1498 if (relative == 2) /* AP relative */
1500 eDebug("AP relative seeking: %lld, at %lld", pts, now);
1502 if (m_tstools.getNextAccessPoint(nextap, now, pts))
1504 pts = now - 90000; /* approx. 1s */
1505 eDebug("AP relative seeking failed!");
1509 eDebug("next ap is %llx\n", pts);
1514 if (m_tstools.getOffset(offset, pts, -1))
1516 eDebug("get offset for pts=%lld failed!", pts);
1520 eDebug("ok, resolved skip (rel: %d, diff %lld), now at %08llx", relative, pts, offset);
1521 current_offset = align(offset, blocksize); /* in case tstools return non-aligned offset */
1524 m_cue->m_lock.Unlock();
1526 for (std::list<std::pair<off_t, off_t> >::const_iterator i(m_source_span.begin()); i != m_source_span.end(); ++i)
1528 long long aligned_start = align(i->first, blocksize);
1529 long long aligned_end = align(i->second, blocksize);
1531 if ((current_offset >= aligned_start) && (current_offset < aligned_end))
1533 start = current_offset;
1534 /* max can not exceed max(size_t). aligned_end - current_offset, however, can. */
1535 if ((aligned_end - current_offset) > max)
1538 size = aligned_end - current_offset;
1539 eDebug("HIT, %lld < %lld < %lld, size: %zd", i->first, current_offset, i->second, size);
1542 if (current_offset < aligned_start)
1544 /* ok, our current offset is in an 'out' zone. */
1545 if ((m_skipmode_m >= 0) || (i == m_source_span.begin()))
1547 /* in normal playback, just start at the next zone. */
1550 /* size is not 64bit! */
1551 if ((i->second - i->first) > max)
1554 size = aligned_end - aligned_start;
1557 if (m_skipmode_m < 0)
1559 eDebug("reached SOF");
1562 m_pvr_thread->sendEvent(eFilePushThread::evtUser);
1566 /* when skipping reverse, however, choose the zone before. */
1568 eDebug("skip to previous block, which is %llx..%llx", i->first, i->second);
1571 aligned_start = align(i->first, blocksize);
1572 aligned_end = align(i->second, blocksize);
1574 if ((aligned_end - aligned_start) > max)
1577 len = aligned_end - aligned_start;
1579 start = aligned_end - len;
1580 eDebug("skipping to %llx, %zd", start, len);
1583 eDebug("result: %llx, %zx (%llx %llx)", start, size, aligned_start, aligned_end);
1588 if(current_offset <0)
1590 if ((current_offset < -m_skipmode_m) && (m_skipmode_m < 0))
1592 eDebug("reached SOF");
1594 m_pvr_thread->sendEvent(eFilePushThread::evtUser);
1596 if (m_source_span.empty())
1598 start = current_offset;
1600 eDebug("NO CUESHEET. (%08lld, %zd)", start, size);
1603 start = current_offset;
1609 void eDVBChannel::AddUse()
1611 if (++m_use_count > 1 && m_state == state_last_instance)
1614 m_stateChanged(this);
1618 void eDVBChannel::ReleaseUse()
1622 m_state = state_release;
1623 m_stateChanged(this);
1625 else if (m_use_count == 1)
1627 m_state = state_last_instance;
1628 m_stateChanged(this);
1632 RESULT eDVBChannel::setChannel(const eDVBChannelID &channelid, ePtr<iDVBFrontendParameters> &feparm)
1635 m_mgr->removeChannel(this);
1640 m_channel_id = channelid;
1641 m_mgr->addChannel(channelid, this);
1645 /* no frontend, no need to tune (must be a streamed service) */
1649 m_state = state_tuning;
1650 /* if tuning fails, shutdown the channel immediately. */
1652 res = m_frontend->get().tune(*feparm);
1653 m_current_frontend_parameters = feparm;
1657 m_state = state_release;
1658 m_stateChanged(this);
1665 RESULT eDVBChannel::connectStateChange(const Slot1<void,iDVBChannel*> &stateChange, ePtr<eConnection> &connection)
1667 connection = new eConnection((iDVBChannel*)this, m_stateChanged.connect(stateChange));
1671 RESULT eDVBChannel::connectEvent(const Slot2<void,iDVBChannel*,int> &event, ePtr<eConnection> &connection)
1673 connection = new eConnection((iDVBChannel*)this, m_event.connect(event));
1677 RESULT eDVBChannel::getState(int &state)
1683 RESULT eDVBChannel::setCIRouting(const eDVBCIRouting &routing)
1688 void eDVBChannel::SDTready(int result)
1690 ePyObject args = PyTuple_New(2), ret;
1694 for (std::vector<ServiceDescriptionSection*>::const_iterator i = m_SDT->getSections().begin(); i != m_SDT->getSections().end(); ++i)
1697 PyTuple_SET_ITEM(args, 0, PyInt_FromLong((*i)->getTransportStreamId()));
1698 PyTuple_SET_ITEM(args, 1, PyInt_FromLong((*i)->getOriginalNetworkId()));
1704 PyTuple_SET_ITEM(args, 0, Py_None);
1705 PyTuple_SET_ITEM(args, 1, Py_None);
1709 ret = PyObject_CallObject(m_tsid_onid_callback, args);
1713 Py_DECREF(m_tsid_onid_callback);
1714 m_tsid_onid_callback = ePyObject();
1715 m_tsid_onid_demux = 0;
1719 int eDVBChannel::reserveDemux()
1721 ePtr<iDVBDemux> dmx;
1722 if (!getDemux(dmx, 0))
1725 if (!dmx->getCADemuxID(id))
1731 RESULT eDVBChannel::requestTsidOnid(ePyObject callback)
1733 if (PyCallable_Check(callback))
1735 if (!getDemux(m_tsid_onid_demux, 0))
1737 m_SDT = new eTable<ServiceDescriptionSection>;
1738 CONNECT(m_SDT->tableReady, eDVBChannel::SDTready);
1739 if (m_SDT->start(m_tsid_onid_demux, eDVBSDTSpec()))
1741 m_tsid_onid_demux = 0;
1746 Py_INCREF(callback);
1747 m_tsid_onid_callback = callback;
1755 RESULT eDVBChannel::getDemux(ePtr<iDVBDemux> &demux, int cap)
1757 ePtr<eDVBAllocatedDemux> &our_demux = (cap & capDecode) ? m_decoder_demux : m_demux;
1759 if (m_frontend == NULL)
1761 /* in dvr mode, we have to stick to a single demux (the one connected to our dvr device) */
1762 our_demux = m_decoder_demux ? m_decoder_demux : m_demux;
1769 if (m_mgr->allocateDemux(m_frontend ? (eDVBRegisteredFrontend*)*m_frontend : (eDVBRegisteredFrontend*)0, our_demux, cap))
1774 /* don't hold a reference to the decoding demux, we don't need it. */
1776 /* FIXME: by dropping the 'allocated demux' in favour of the 'iDVBDemux',
1777 the refcount is lost. thus, decoding demuxes are never allocated.
1779 this poses a big problem for PiP. */
1781 if (cap & capHoldDecodeReference) // this is set in eDVBResourceManager::allocateDemux for Dm500HD/DM800 and DM8000
1783 else if (cap & capDecode)
1792 RESULT eDVBChannel::getFrontend(ePtr<iDVBFrontend> &frontend)
1797 frontend = &m_frontend->get();
1803 RESULT eDVBChannel::getCurrentFrontendParameters(ePtr<iDVBFrontendParameters> ¶m)
1805 param = m_current_frontend_parameters;
1809 RESULT eDVBChannel::playFile(const char *file)
1811 eRawFile *f = new eRawFile();
1812 ePtr<iTsSource> source = f;
1814 if (f->open(file) < 0)
1816 eDebug("can't open PVR file %s (%m)", file);
1820 return playSource(source, file);
1823 RESULT eDVBChannel::playSource(ePtr<iTsSource> &source, const char *streaminfo_file)
1825 ASSERT(!m_frontend);
1828 m_pvr_thread->stop();
1829 delete m_pvr_thread;
1833 if (!source->valid())
1835 eDebug("PVR source is not valid!");
1839 m_tstools.setSource(source, streaminfo_file);
1841 /* DON'T EVEN THINK ABOUT FIXING THIS. FIX THE ATI SOURCES FIRST,
1842 THEN DO A REAL FIX HERE! */
1844 if (m_pvr_fd_dst < 0)
1846 /* (this codepath needs to be improved anyway.) */
1847 #if HAVE_DVB_API_VERSION < 3
1848 m_pvr_fd_dst = open("/dev/pvr", O_WRONLY);
1849 if (m_pvr_fd_dst < 0)
1851 eDebug("can't open /dev/pvr - you need to buy the new(!) $$$ box! (%m)"); // or wait for the driver to be improved.
1855 ePtr<eDVBAllocatedDemux> &demux = m_demux ? m_demux : m_decoder_demux;
1858 m_pvr_fd_dst = demux->get().openDVR(O_WRONLY);
1859 if (m_pvr_fd_dst < 0)
1861 eDebug("can't open /dev/dvb/adapterX/dvrX - you need to buy the new(!) $$$ box! (%m)"); // or wait for the driver to be improved.
1867 eDebug("no demux allocated yet.. so its not possible to open the dvr device!!");
1873 m_pvr_thread = new eDVBChannelFilePush();
1874 m_pvr_thread->enablePVRCommit(1);
1875 /* If the source specifies a length, it's a file. If not, it's a stream */
1876 m_pvr_thread->setStreamMode(source->length() <= 0);
1877 m_pvr_thread->setScatterGather(this);
1879 m_event(this, evtPreStart);
1881 m_pvr_thread->start(source, m_pvr_fd_dst);
1882 CONNECT(m_pvr_thread->m_event, eDVBChannel::pvrEvent);
1885 m_stateChanged(this);
1890 void eDVBChannel::stopSource()
1894 m_pvr_thread->stop();
1895 delete m_pvr_thread;
1898 if (m_pvr_fd_dst >= 0)
1899 ::close(m_pvr_fd_dst);
1901 m_tstools.setSource(d);
1904 void eDVBChannel::stopFile()
1909 void eDVBChannel::setCueSheet(eCueSheet *cuesheet)
1911 m_conn_cueSheetEvent = 0;
1914 m_cue->connectEvent(slot(*this, &eDVBChannel::cueSheetEvent), m_conn_cueSheetEvent);
1917 RESULT eDVBChannel::getLength(pts_t &len)
1919 return m_tstools.calcLen(len);
1922 RESULT eDVBChannel::getCurrentPosition(iDVBDemux *decoding_demux, pts_t &pos, int mode)
1924 if (!decoding_demux)
1931 if (mode == 0) /* demux */
1933 r = decoding_demux->getSTC(now, 0);
1936 eDebug("demux getSTC failed");
1940 now = pos; /* fixup supplied */
1942 off_t off = 0; /* TODO: fixme */
1943 r = m_tstools.fixupPTS(off, now);
1946 eDebug("fixup PTS failed");
1955 void eDVBChannel::flushPVR(iDVBDemux *decoding_demux)
1957 /* when seeking, we have to ensure that all buffers are flushed.
1958 there are basically 3 buffers:
1959 a.) the filepush's internal buffer
1960 b.) the PVR buffer (before demux)
1961 c.) the ratebuffer (after demux)
1963 it's important to clear them in the correct order, otherwise
1964 the ratebuffer (for example) would immediately refill from
1965 the not-yet-flushed PVR buffer.
1968 m_pvr_thread->pause();
1969 /* flush internal filepush buffer */
1970 m_pvr_thread->flush();
1971 /* HACK: flush PVR buffer */
1972 ::ioctl(m_pvr_fd_dst, 0);
1974 /* flush ratebuffers (video, audio) */
1976 decoding_demux->flush();
1978 /* demux will also flush all decoder.. */
1979 /* resume will re-query the SG */
1980 m_pvr_thread->resume();
1983 DEFINE_REF(eCueSheet);
1985 eCueSheet::eCueSheet()
1987 m_skipmode_ratio = 0;
1990 void eCueSheet::seekTo(int relative, const pts_t &pts)
1993 m_seek_requests.push_back(std::pair<int, pts_t>(relative, pts));
1998 void eCueSheet::clear()
2005 void eCueSheet::addSourceSpan(const pts_t &begin, const pts_t &end)
2007 ASSERT(begin < end);
2009 m_spans.push_back(std::pair<pts_t, pts_t>(begin, end));
2013 void eCueSheet::commitSpans()
2015 m_event(evtSpanChanged);
2018 void eCueSheet::setSkipmode(const pts_t &ratio)
2021 m_skipmode_ratio = ratio;
2023 m_event(evtSkipmode);
2026 void eCueSheet::setDecodingDemux(iDVBDemux *demux, iTSMPEGDecoder *decoder)
2028 m_decoding_demux = demux;
2029 m_decoder = decoder;
2032 RESULT eCueSheet::connectEvent(const Slot1<void,int> &event, ePtr<eConnection> &connection)
2034 connection = new eConnection(this, m_event.connect(event));