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, int &system)
829 system = iDVBFrontend::feSatellite;
832 ePtr<iDVBFrontendParameters> feparm;
833 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, int &system, bool simulate)
856 std::list<active_channel> &active_channels = simulate ? m_active_simulate_channels : m_active_channels;
858 system = iDVBFrontend::feSatellite;
859 if (!simulate && m_cached_channel)
861 eDVBChannel *cache_chan = (eDVBChannel*)&(*m_cached_channel);
862 if(channelid==cache_chan->getChannelID())
863 return tuner_type_channel_default(m_list, channelid, system);
866 /* first, check if a channel is already existing. */
867 // eDebug("allocate channel.. %04x:%04x", channelid.transport_stream_id.get(), channelid.original_network_id.get());
868 for (std::list<active_channel>::iterator i(active_channels.begin()); i != active_channels.end(); ++i)
870 // eDebug("available channel.. %04x:%04x", i->m_channel_id.transport_stream_id.get(), i->m_channel_id.original_network_id.get());
871 if (i->m_channel_id == channelid)
873 // eDebug("found shared channel..");
874 return tuner_type_channel_default(m_list, channelid, system);
878 int *decremented_cached_channel_fe_usecount=NULL,
879 *decremented_fe_usecount=NULL;
881 for (std::list<active_channel>::iterator i(active_channels.begin()); i != active_channels.end(); ++i)
883 eSmartPtrList<eDVBRegisteredFrontend> &frontends = simulate ? m_simulate_frontend : m_frontend;
884 // eDebug("available channel.. %04x:%04x", i->m_channel_id.transport_stream_id.get(), i->m_channel_id.original_network_id.get());
885 if (i->m_channel_id == ignore)
887 eDVBChannel *channel = (eDVBChannel*) &(*i->m_channel);
888 // one eUsePtr<iDVBChannel> is used in eDVBServicePMTHandler
889 // another on eUsePtr<iDVBChannel> is used in the eDVBScan instance used in eDVBServicePMTHandler (for SDT scan)
890 // so we must check here if usecount is 3 (when the channel is equal to the cached channel)
891 // or 2 when the cached channel is not equal to the compared channel
892 if (channel == &(*m_cached_channel) ? channel->getUseCount() == 3 : channel->getUseCount() == 2) // channel only used once..
894 ePtr<iDVBFrontend> fe;
895 if (!i->m_channel->getFrontend(fe))
897 for (eSmartPtrList<eDVBRegisteredFrontend>::iterator ii(frontends.begin()); ii != frontends.end(); ++ii)
899 if ( &(*fe) == &(*ii->m_frontend) )
902 decremented_fe_usecount = &ii->m_inuse;
903 if (channel == &(*m_cached_channel))
904 decremented_cached_channel_fe_usecount = decremented_fe_usecount;
914 if (!decremented_cached_channel_fe_usecount)
916 if (m_cached_channel)
918 eDVBChannel *channel = (eDVBChannel*) &(*m_cached_channel);
919 if (channel->getUseCount() == 1)
921 ePtr<iDVBFrontend> fe;
922 if (!channel->getFrontend(fe))
924 eSmartPtrList<eDVBRegisteredFrontend> &frontends = simulate ? m_simulate_frontend : m_frontend;
925 for (eSmartPtrList<eDVBRegisteredFrontend>::iterator ii(frontends.begin()); ii != frontends.end(); ++ii)
927 if ( &(*fe) == &(*ii->m_frontend) )
930 decremented_cached_channel_fe_usecount = &ii->m_inuse;
939 decremented_cached_channel_fe_usecount=NULL;
941 ePtr<iDVBFrontendParameters> feparm;
945 eDebug("no channel list set!");
949 if (m_list->getChannelFrontendData(channelid, feparm))
951 eDebug("channel not found!");
954 feparm->getSystem(system);
956 ret = canAllocateFrontend(feparm, simulate);
959 if (decremented_fe_usecount)
960 ++(*decremented_fe_usecount);
961 if (decremented_cached_channel_fe_usecount)
962 ++(*decremented_cached_channel_fe_usecount);
967 bool eDVBResourceManager::canMeasureFrontendInputPower()
969 for (eSmartPtrList<eDVBRegisteredFrontend>::iterator i(m_frontend.begin()); i != m_frontend.end(); ++i)
971 return i->m_frontend->readInputpower() >= 0;
976 class eDVBChannelFilePush: public eFilePushThread
979 eDVBChannelFilePush() { setIFrameSearch(0); setTimebaseChange(0); }
980 void setIFrameSearch(int enabled) { m_iframe_search = enabled; m_iframe_state = 0; }
982 /* "timebase change" is for doing trickmode playback at an exact speed, even when pictures are skipped. */
983 /* you need to set it to 1/16 if you want 16x playback, for example. you need video master sync. */
984 void setTimebaseChange(int ratio) { m_timebase_change = ratio; } /* 16bit fixpoint, 0 for disable */
986 int m_iframe_search, m_iframe_state, m_pid;
987 int m_timebase_change;
988 int filterRecordData(const unsigned char *data, int len, size_t ¤t_span_remaining);
991 int eDVBChannelFilePush::filterRecordData(const unsigned char *_data, int len, size_t ¤t_span_remaining)
994 if (m_timebase_change)
996 eDebug("timebase change: %d", m_timebase_change);
998 for (offset = 0; offset < len; offset += 188)
1000 unsigned char *pkt = (unsigned char*)_data + offset;
1001 if (pkt[1] & 0x40) /* pusi */
1003 if (pkt[3] & 0x20) // adaption field present?
1004 pkt += pkt[4] + 4 + 1; /* skip adaption field and header */
1006 pkt += 4; /* skip header */
1007 if (pkt[0] || pkt[1] || (pkt[2] != 1))
1009 eWarning("broken startcode");
1015 if (pkt[7] & 0x80) // PTS present?
1017 pts = ((unsigned long long)(pkt[ 9]&0xE)) << 29;
1018 pts |= ((unsigned long long)(pkt[10]&0xFF)) << 22;
1019 pts |= ((unsigned long long)(pkt[11]&0xFE)) << 14;
1020 pts |= ((unsigned long long)(pkt[12]&0xFF)) << 7;
1021 pts |= ((unsigned long long)(pkt[13]&0xFE)) >> 1;
1025 RESULT r = m_tstools.fixupPTS(off, pts);
1027 eWarning("fixup PTS while trickmode playback failed.\n");
1030 int sec = pts / 90000;
1031 int frm = pts % 90000;
1039 // eDebug("original, fixed pts: %016llx %d:%02d:%02d:%02d:%05d", pts, d, hr, min, sec, frm);
1041 pts += 0x80000000LL;
1042 pts *= m_timebase_change;
1054 // eDebug("new pts (after timebase change): %016llx %d:%02d:%02d:%02d:%05d", pts, d, hr, min, sec, frm);
1062 pkt[9] |= (pts >> 29) & 0xE;
1063 pkt[10] |= (pts >> 22) & 0xFF;
1064 pkt[11] |= (pts >> 14) & 0xFE;
1065 pkt[12] |= (pts >> 7) & 0xFF;
1066 pkt[13] |= (pts << 1) & 0xFE;
1074 if (!m_iframe_search)
1077 unsigned char *data = (unsigned char*)_data; /* remove that const. we know what we are doing. */
1079 // eDebug("filterRecordData, size=%d (mod 188=%d), first byte is %02x", len, len %188, data[0]);
1081 unsigned char *d = data;
1082 while ((d + 3 < data + len) && (d = (unsigned char*)memmem(d, data + len - d, "\x00\x00\x01", 3)))
1084 int offset = d - data;
1085 int ts_offset = offset - offset % 188; /* offset to the start of TS packet */
1086 unsigned char *ts = data + ts_offset;
1087 int pid = ((ts[1] << 8) | ts[2]) & 0x1FFF;
1089 if ((d[3] == 0 || d[3] == 0x09 && d[-1] == 0 && (ts[1] & 0x40)) && (m_pid == pid)) /* picture start */
1091 int picture_type = (d[3]==0 ? (d[5] >> 3) & 7 : (d[4] >> 5) + 1);
1094 // eDebug("%d-frame at %d, offset in TS packet: %d, pid=%04x", picture_type, offset, offset % 188, pid);
1096 if (m_iframe_state == 1)
1098 /* we are allowing data, and stop allowing data on the next frame.
1099 we now found a frame. so stop here. */
1100 memset(data + offset, 0, 188 - (offset%188)); /* zero out rest of TS packet */
1101 current_span_remaining = 0;
1103 unsigned char *fts = ts + 188;
1104 while (fts < (data + len))
1107 fts[2] |= 0xff; /* drop packet */
1111 return len; // ts_offset + 188; /* deliver this packet, but not more. */
1114 if (picture_type != 1) /* we are only interested in I frames */
1117 unsigned char *fts = data;
1121 fts[2] |= 0xff; /* drop packet */
1128 } else if ((d[3] & 0xF0) == 0xE0) /* video stream */
1130 /* verify that this is actually a PES header, not just some ES data */
1131 if (ts[1] & 0x40) /* PUSI set */
1133 int payload_start = 4;
1134 if (ts[3] & 0x20) /* adaptation field present */
1135 payload_start += ts[4] + 1; /* skip AF */
1136 if (payload_start == (offset%188)) /* the 00 00 01 should be directly at the payload start, otherwise it's not a PES header */
1140 eDebug("now locked to pid %04x (%02x %02x %02x %02x)", pid, ts[0], ts[1], ts[2], ts[3]);
1148 d += 4; /* ignore */
1151 if (m_iframe_state == 1)
1154 return 0; /* we need find an iframe first */
1160 DEFINE_REF(eDVBChannel);
1162 eDVBChannel::eDVBChannel(eDVBResourceManager *mgr, eDVBAllocatedFrontend *frontend): m_state(state_idle), m_mgr(mgr)
1164 m_frontend = frontend;
1169 m_skipmode_n = m_skipmode_m = m_skipmode_frames = 0;
1172 m_frontend->get().connectStateChange(slot(*this, &eDVBChannel::frontendStateChanged), m_conn_frontendStateChanged);
1175 eDVBChannel::~eDVBChannel()
1178 m_mgr->removeChannel(this);
1183 void eDVBChannel::frontendStateChanged(iDVBFrontend*fe)
1185 int state, ourstate = 0;
1187 /* if we are already in shutdown, don't change state. */
1188 if (m_state == state_release)
1191 if (fe->getState(state))
1194 if (state == iDVBFrontend::stateLock)
1196 eDebug("OURSTATE: ok");
1197 ourstate = state_ok;
1198 } else if (state == iDVBFrontend::stateTuning)
1200 eDebug("OURSTATE: tuning");
1201 ourstate = state_tuning;
1202 } else if (state == iDVBFrontend::stateLostLock)
1204 /* on managed channels, we try to retune in order to re-acquire lock. */
1205 if (m_current_frontend_parameters)
1207 eDebug("OURSTATE: lost lock, trying to retune");
1208 ourstate = state_tuning;
1209 m_frontend->get().tune(*m_current_frontend_parameters);
1211 /* on unmanaged channels, we don't do this. the client will do this. */
1213 eDebug("OURSTATE: lost lock, unavailable now.");
1214 ourstate = state_unavailable;
1216 } else if (state == iDVBFrontend::stateFailed)
1218 #ifdef BUILD_VUPLUS /* ikseong */
1219 if (m_current_frontend_parameters)
1221 eDebug("OURSTATE: lost lock, trying to retune");
1222 ourstate = state_tuning;
1223 m_frontend->get().tune(*m_current_frontend_parameters);
1227 eDebug("OURSTATE: failed");
1228 ourstate = state_failed;
1231 eDebug("OURSTATE: failed");
1232 ourstate = state_failed;
1235 eFatal("state unknown");
1237 if (ourstate != m_state)
1240 m_stateChanged(this);
1244 void eDVBChannel::pvrEvent(int event)
1248 case eFilePushThread::evtEOF:
1249 eDebug("eDVBChannel: End of file!");
1250 m_event(this, evtEOF);
1252 case eFilePushThread::evtUser: /* start */
1254 m_event(this, evtSOF);
1259 void eDVBChannel::cueSheetEvent(int event)
1261 /* we might end up here if playing failed or stopped, but the client hasn't (yet) noted. */
1266 case eCueSheet::evtSeek:
1268 flushPVR(m_cue->m_decoding_demux);
1270 case eCueSheet::evtSkipmode:
1273 m_cue->m_lock.WrLock();
1274 m_cue->m_seek_requests.push_back(std::pair<int, pts_t>(1, 0)); /* resync */
1275 m_cue->m_lock.Unlock();
1276 eRdLocker l(m_cue->m_lock);
1277 if (m_cue->m_skipmode_ratio)
1279 int bitrate = m_tstools.calcBitrate(); /* in bits/s */
1280 eDebug("skipmode ratio is %lld:90000, bitrate is %d bit/s", m_cue->m_skipmode_ratio, bitrate);
1281 /* i agree that this might look a bit like black magic. */
1282 m_skipmode_n = 512*1024; /* must be 1 iframe at least. */
1283 m_skipmode_m = bitrate / 8 / 90000 * m_cue->m_skipmode_ratio / 8;
1284 m_skipmode_frames = m_cue->m_skipmode_ratio / 90000;
1285 m_skipmode_frames_remainder = 0;
1287 if (m_cue->m_skipmode_ratio < 0)
1288 m_skipmode_m -= m_skipmode_n;
1290 eDebug("resolved to: %d %d", m_skipmode_m, m_skipmode_n);
1292 if (abs(m_skipmode_m) < abs(m_skipmode_n))
1294 eWarning("something is wrong with this calculation");
1295 m_skipmode_frames = m_skipmode_n = m_skipmode_m = 0;
1299 eDebug("skipmode ratio is 0, normal play");
1300 m_skipmode_frames = m_skipmode_n = m_skipmode_m = 0;
1303 m_pvr_thread->setIFrameSearch(m_skipmode_n != 0);
1304 if (m_cue->m_skipmode_ratio != 0)
1305 m_pvr_thread->setTimebaseChange(0x10000 * 9000 / (m_cue->m_skipmode_ratio / 10)); /* negative values are also ok */
1307 m_pvr_thread->setTimebaseChange(0); /* normal playback */
1308 eDebug("flush pvr");
1309 flushPVR(m_cue->m_decoding_demux);
1313 case eCueSheet::evtSpanChanged:
1315 m_source_span.clear();
1316 for (std::list<std::pair<pts_t, pts_t> >::const_iterator i(m_cue->m_spans.begin()); i != m_cue->m_spans.end(); ++i)
1318 off_t offset_in, offset_out;
1319 pts_t pts_in = i->first, pts_out = i->second;
1320 if (m_tstools.getOffset(offset_in, pts_in, -1) || m_tstools.getOffset(offset_out, pts_out, 1))
1322 eDebug("span translation failed.\n");
1325 eDebug("source span: %llx .. %llx, translated to %llx..%llx", pts_in, pts_out, offset_in, offset_out);
1326 m_source_span.push_back(std::pair<off_t, off_t>(offset_in, offset_out));
1333 /* align toward zero */
1334 static inline long long align(long long x, int align)
1349 /* align toward zero */
1350 static inline long long align_with_len(long long x, int align, size_t &len)
1367 /* remember, this gets called from another thread. */
1368 void eDVBChannel::getNextSourceSpan(off_t current_offset, size_t bytes_read, off_t &start, size_t &size)
1370 const int blocksize = 188;
1371 unsigned int max = align(10*1024*1024, blocksize);
1372 current_offset = align(current_offset, blocksize);
1376 eDebug("no cue sheet. forcing normal play");
1377 start = current_offset;
1384 eDebug("skipmode %d:%d (x%d)", m_skipmode_m, m_skipmode_n, m_skipmode_frames);
1385 max = align(m_skipmode_n, blocksize);
1388 eDebug("getNextSourceSpan, current offset is %08lld, m_skipmode_m = %d!", current_offset, m_skipmode_m);
1389 int frame_skip_success = 0;
1393 int frames_to_skip = m_skipmode_frames + m_skipmode_frames_remainder;
1394 eDebug("we are at %lld, and we try to skip %d+%d frames from here", current_offset, m_skipmode_frames, m_skipmode_frames_remainder);
1396 off_t iframe_start = current_offset;
1397 int frames_skipped = frames_to_skip;
1398 if (!m_tstools.findNextPicture(iframe_start, iframe_len, frames_skipped))
1400 m_skipmode_frames_remainder = frames_to_skip - frames_skipped;
1401 eDebug("successfully skipped %d (out of %d, rem now %d) frames.", frames_skipped, frames_to_skip, m_skipmode_frames_remainder);
1402 current_offset = align_with_len(iframe_start, blocksize, iframe_len);
1403 max = align(iframe_len + 187, blocksize);
1404 frame_skip_success = 1;
1407 m_skipmode_frames_remainder = 0;
1408 eDebug("frame skipping failed, reverting to byte-skipping");
1412 if (!frame_skip_success)
1414 current_offset += align(m_skipmode_m, blocksize);
1415 if(current_offset < 0)
1421 eDebug("we are at %lld, and we try to find the iframe here:", current_offset);
1423 off_t start_offset = current_offset;
1424 off_t new_offset = start_offset;
1425 int direction = (m_skipmode_m < 0) ? -1 : +1;
1426 if (m_tstools.findFrame(start_offset, new_offset, iframe_len, direction))
1430 current_offset = align_with_len(new_offset, blocksize, iframe_len);
1431 max = align(iframe_len, blocksize);
1437 m_cue->m_lock.RdLock();
1439 while (!m_cue->m_seek_requests.empty())
1441 std::pair<int, pts_t> seek = m_cue->m_seek_requests.front();
1442 m_cue->m_lock.Unlock();
1443 m_cue->m_lock.WrLock();
1444 m_cue->m_seek_requests.pop_front();
1445 m_cue->m_lock.Unlock();
1446 m_cue->m_lock.RdLock();
1447 int relative = seek.first;
1448 pts_t pts = seek.second;
1453 if (!m_cue->m_decoder)
1455 eDebug("no decoder - can't seek relative");
1458 if (m_cue->m_decoder->getPTS(0, now))
1460 eDebug("decoder getPTS failed, can't seek relative");
1463 if (!m_cue->m_decoding_demux)
1465 eDebug("getNextSourceSpan, no decoding demux. couldn't seek to %llx... ignore request!", pts);
1466 start = current_offset;
1470 if (getCurrentPosition(m_cue->m_decoding_demux, now, 1))
1472 eDebug("seekTo: getCurrentPosition failed!");
1475 } else if (pts < 0) /* seek relative to end */
1478 if (!getLength(len))
1480 eDebug("seeking relative to end. len=%lld, seek = %lld", len, pts);
1484 eWarning("getLength failed - can't seek relative to end!");
1489 if (relative == 1) /* pts relative */
1500 if (relative == 2) /* AP relative */
1502 eDebug("AP relative seeking: %lld, at %lld", pts, now);
1504 if (m_tstools.getNextAccessPoint(nextap, now, pts))
1506 pts = now - 90000; /* approx. 1s */
1507 eDebug("AP relative seeking failed!");
1511 eDebug("next ap is %llx\n", pts);
1516 if (m_tstools.getOffset(offset, pts, -1))
1518 eDebug("get offset for pts=%lld failed!", pts);
1522 eDebug("ok, resolved skip (rel: %d, diff %lld), now at %08llx", relative, pts, offset);
1523 current_offset = align(offset, blocksize); /* in case tstools return non-aligned offset */
1526 m_cue->m_lock.Unlock();
1528 for (std::list<std::pair<off_t, off_t> >::const_iterator i(m_source_span.begin()); i != m_source_span.end(); ++i)
1530 long long aligned_start = align(i->first, blocksize);
1531 long long aligned_end = align(i->second, blocksize);
1533 if ((current_offset >= aligned_start) && (current_offset < aligned_end))
1535 start = current_offset;
1536 /* max can not exceed max(size_t). aligned_end - current_offset, however, can. */
1537 if ((aligned_end - current_offset) > max)
1540 size = aligned_end - current_offset;
1541 eDebug("HIT, %lld < %lld < %lld, size: %zd", i->first, current_offset, i->second, size);
1544 if (current_offset < aligned_start)
1546 /* ok, our current offset is in an 'out' zone. */
1547 if ((m_skipmode_m >= 0) || (i == m_source_span.begin()))
1549 /* in normal playback, just start at the next zone. */
1552 /* size is not 64bit! */
1553 if ((i->second - i->first) > max)
1556 size = aligned_end - aligned_start;
1559 if (m_skipmode_m < 0)
1561 eDebug("reached SOF");
1564 m_pvr_thread->sendEvent(eFilePushThread::evtUser);
1568 /* when skipping reverse, however, choose the zone before. */
1570 eDebug("skip to previous block, which is %llx..%llx", i->first, i->second);
1573 aligned_start = align(i->first, blocksize);
1574 aligned_end = align(i->second, blocksize);
1576 if ((aligned_end - aligned_start) > max)
1579 len = aligned_end - aligned_start;
1581 start = aligned_end - len;
1582 eDebug("skipping to %llx, %zd", start, len);
1585 eDebug("result: %llx, %zx (%llx %llx)", start, size, aligned_start, aligned_end);
1590 if(current_offset <0)
1592 if ((current_offset < -m_skipmode_m) && (m_skipmode_m < 0))
1594 eDebug("reached SOF");
1596 m_pvr_thread->sendEvent(eFilePushThread::evtUser);
1598 if (m_source_span.empty())
1600 start = current_offset;
1602 eDebug("NO CUESHEET. (%08lld, %zd)", start, size);
1605 start = current_offset;
1611 void eDVBChannel::AddUse()
1613 if (++m_use_count > 1 && m_state == state_last_instance)
1616 m_stateChanged(this);
1620 void eDVBChannel::ReleaseUse()
1624 m_state = state_release;
1625 m_stateChanged(this);
1627 else if (m_use_count == 1)
1629 m_state = state_last_instance;
1630 m_stateChanged(this);
1634 RESULT eDVBChannel::setChannel(const eDVBChannelID &channelid, ePtr<iDVBFrontendParameters> &feparm)
1637 m_mgr->removeChannel(this);
1642 m_channel_id = channelid;
1643 m_mgr->addChannel(channelid, this);
1647 /* no frontend, no need to tune (must be a streamed service) */
1651 m_state = state_tuning;
1652 /* if tuning fails, shutdown the channel immediately. */
1654 res = m_frontend->get().tune(*feparm);
1655 m_current_frontend_parameters = feparm;
1659 m_state = state_release;
1660 m_stateChanged(this);
1667 RESULT eDVBChannel::connectStateChange(const Slot1<void,iDVBChannel*> &stateChange, ePtr<eConnection> &connection)
1669 connection = new eConnection((iDVBChannel*)this, m_stateChanged.connect(stateChange));
1673 RESULT eDVBChannel::connectEvent(const Slot2<void,iDVBChannel*,int> &event, ePtr<eConnection> &connection)
1675 connection = new eConnection((iDVBChannel*)this, m_event.connect(event));
1679 RESULT eDVBChannel::getState(int &state)
1685 RESULT eDVBChannel::setCIRouting(const eDVBCIRouting &routing)
1690 void eDVBChannel::SDTready(int result)
1692 ePyObject args = PyTuple_New(2), ret;
1696 for (std::vector<ServiceDescriptionSection*>::const_iterator i = m_SDT->getSections().begin(); i != m_SDT->getSections().end(); ++i)
1699 PyTuple_SET_ITEM(args, 0, PyInt_FromLong((*i)->getTransportStreamId()));
1700 PyTuple_SET_ITEM(args, 1, PyInt_FromLong((*i)->getOriginalNetworkId()));
1706 PyTuple_SET_ITEM(args, 0, Py_None);
1707 PyTuple_SET_ITEM(args, 1, Py_None);
1711 ret = PyObject_CallObject(m_tsid_onid_callback, args);
1715 Py_DECREF(m_tsid_onid_callback);
1716 m_tsid_onid_callback = ePyObject();
1717 m_tsid_onid_demux = 0;
1721 int eDVBChannel::reserveDemux()
1723 ePtr<iDVBDemux> dmx;
1724 if (!getDemux(dmx, 0))
1727 if (!dmx->getCADemuxID(id))
1733 RESULT eDVBChannel::requestTsidOnid(ePyObject callback)
1735 if (PyCallable_Check(callback))
1737 if (!getDemux(m_tsid_onid_demux, 0))
1739 m_SDT = new eTable<ServiceDescriptionSection>;
1740 CONNECT(m_SDT->tableReady, eDVBChannel::SDTready);
1741 if (m_SDT->start(m_tsid_onid_demux, eDVBSDTSpec()))
1743 m_tsid_onid_demux = 0;
1748 Py_INCREF(callback);
1749 m_tsid_onid_callback = callback;
1757 RESULT eDVBChannel::getDemux(ePtr<iDVBDemux> &demux, int cap)
1759 ePtr<eDVBAllocatedDemux> &our_demux = (cap & capDecode) ? m_decoder_demux : m_demux;
1761 if (m_frontend == NULL)
1763 /* in dvr mode, we have to stick to a single demux (the one connected to our dvr device) */
1764 our_demux = m_decoder_demux ? m_decoder_demux : m_demux;
1771 if (m_mgr->allocateDemux(m_frontend ? (eDVBRegisteredFrontend*)*m_frontend : (eDVBRegisteredFrontend*)0, our_demux, cap))
1776 /* don't hold a reference to the decoding demux, we don't need it. */
1778 /* FIXME: by dropping the 'allocated demux' in favour of the 'iDVBDemux',
1779 the refcount is lost. thus, decoding demuxes are never allocated.
1781 this poses a big problem for PiP. */
1783 if (cap & capHoldDecodeReference) // this is set in eDVBResourceManager::allocateDemux for Dm500HD/DM800 and DM8000
1785 else if (cap & capDecode)
1794 RESULT eDVBChannel::getFrontend(ePtr<iDVBFrontend> &frontend)
1799 frontend = &m_frontend->get();
1805 RESULT eDVBChannel::getCurrentFrontendParameters(ePtr<iDVBFrontendParameters> ¶m)
1807 param = m_current_frontend_parameters;
1811 RESULT eDVBChannel::playFile(const char *file)
1813 eRawFile *f = new eRawFile();
1814 ePtr<iTsSource> source = f;
1816 if (f->open(file) < 0)
1818 eDebug("can't open PVR file %s (%m)", file);
1822 return playSource(source, file);
1825 RESULT eDVBChannel::playSource(ePtr<iTsSource> &source, const char *streaminfo_file)
1827 ASSERT(!m_frontend);
1830 m_pvr_thread->stop();
1831 delete m_pvr_thread;
1835 if (!source->valid())
1837 eDebug("PVR source is not valid!");
1841 m_tstools.setSource(source, streaminfo_file);
1843 /* DON'T EVEN THINK ABOUT FIXING THIS. FIX THE ATI SOURCES FIRST,
1844 THEN DO A REAL FIX HERE! */
1846 if (m_pvr_fd_dst < 0)
1848 /* (this codepath needs to be improved anyway.) */
1849 #if HAVE_DVB_API_VERSION < 3
1850 m_pvr_fd_dst = open("/dev/pvr", O_WRONLY);
1851 if (m_pvr_fd_dst < 0)
1853 eDebug("can't open /dev/pvr - you need to buy the new(!) $$$ box! (%m)"); // or wait for the driver to be improved.
1857 ePtr<eDVBAllocatedDemux> &demux = m_demux ? m_demux : m_decoder_demux;
1860 m_pvr_fd_dst = demux->get().openDVR(O_WRONLY);
1861 if (m_pvr_fd_dst < 0)
1863 eDebug("can't open /dev/dvb/adapterX/dvrX - you need to buy the new(!) $$$ box! (%m)"); // or wait for the driver to be improved.
1869 eDebug("no demux allocated yet.. so its not possible to open the dvr device!!");
1875 m_pvr_thread = new eDVBChannelFilePush();
1876 m_pvr_thread->enablePVRCommit(1);
1877 /* If the source specifies a length, it's a file. If not, it's a stream */
1878 m_pvr_thread->setStreamMode(source->length() <= 0);
1879 m_pvr_thread->setScatterGather(this);
1881 m_event(this, evtPreStart);
1883 m_pvr_thread->start(source, m_pvr_fd_dst);
1884 CONNECT(m_pvr_thread->m_event, eDVBChannel::pvrEvent);
1887 m_stateChanged(this);
1892 void eDVBChannel::stopSource()
1896 m_pvr_thread->stop();
1897 delete m_pvr_thread;
1900 if (m_pvr_fd_dst >= 0)
1901 ::close(m_pvr_fd_dst);
1903 m_tstools.setSource(d);
1906 void eDVBChannel::stopFile()
1911 void eDVBChannel::setCueSheet(eCueSheet *cuesheet)
1913 m_conn_cueSheetEvent = 0;
1916 m_cue->connectEvent(slot(*this, &eDVBChannel::cueSheetEvent), m_conn_cueSheetEvent);
1919 RESULT eDVBChannel::getLength(pts_t &len)
1921 return m_tstools.calcLen(len);
1924 RESULT eDVBChannel::getCurrentPosition(iDVBDemux *decoding_demux, pts_t &pos, int mode)
1926 if (!decoding_demux)
1933 if (mode == 0) /* demux */
1935 r = decoding_demux->getSTC(now, 0);
1938 eDebug("demux getSTC failed");
1942 now = pos; /* fixup supplied */
1944 off_t off = 0; /* TODO: fixme */
1945 r = m_tstools.fixupPTS(off, now);
1948 eDebug("fixup PTS failed");
1957 void eDVBChannel::flushPVR(iDVBDemux *decoding_demux)
1959 /* when seeking, we have to ensure that all buffers are flushed.
1960 there are basically 3 buffers:
1961 a.) the filepush's internal buffer
1962 b.) the PVR buffer (before demux)
1963 c.) the ratebuffer (after demux)
1965 it's important to clear them in the correct order, otherwise
1966 the ratebuffer (for example) would immediately refill from
1967 the not-yet-flushed PVR buffer.
1970 m_pvr_thread->pause();
1971 /* flush internal filepush buffer */
1972 m_pvr_thread->flush();
1973 /* HACK: flush PVR buffer */
1974 ::ioctl(m_pvr_fd_dst, 0);
1976 /* flush ratebuffers (video, audio) */
1978 decoding_demux->flush();
1980 /* demux will also flush all decoder.. */
1981 /* resume will re-query the SG */
1982 m_pvr_thread->resume();
1985 DEFINE_REF(eCueSheet);
1987 eCueSheet::eCueSheet()
1989 m_skipmode_ratio = 0;
1992 void eCueSheet::seekTo(int relative, const pts_t &pts)
1995 m_seek_requests.push_back(std::pair<int, pts_t>(relative, pts));
2000 void eCueSheet::clear()
2007 void eCueSheet::addSourceSpan(const pts_t &begin, const pts_t &end)
2009 ASSERT(begin < end);
2011 m_spans.push_back(std::pair<pts_t, pts_t>(begin, end));
2015 void eCueSheet::commitSpans()
2017 m_event(evtSpanChanged);
2020 void eCueSheet::setSkipmode(const pts_t &ratio)
2023 m_skipmode_ratio = ratio;
2025 m_event(evtSkipmode);
2028 void eCueSheet::setDecodingDemux(iDVBDemux *demux, iTSMPEGDecoder *decoder)
2030 m_decoding_demux = demux;
2031 m_decoder = decoder;
2034 RESULT eCueSheet::connectEvent(const Slot1<void,int> &event, ePtr<eConnection> &connection)
2036 connection = new eConnection(this, m_event.connect(event));