X-Git-Url: http://code.vuplus.com/gitweb/?p=vuplus_dvbapp;a=blobdiff_plain;f=lib%2Fdvb%2Fdvb.cpp;h=852c4034aec4fae7f399ff982e71875fb21a649e;hp=6f9a67fbd092002b4b6818805a6a75eb6c29b2b5;hb=d8e08fe0a7304ed06b3de0b9ad6d4265ec8063b8;hpb=e0d8ce8d7dc7239ff353f09c15b739f1b969cdfb diff --git a/lib/dvb/dvb.cpp b/lib/dvb/dvb.cpp index 6f9a67f..852c403 100644 --- a/lib/dvb/dvb.cpp +++ b/lib/dvb/dvb.cpp @@ -6,12 +6,16 @@ #include #include +#include +#include + #include #include #include #include #include #include +#include DEFINE_REF(eDVBRegisteredFrontend); DEFINE_REF(eDVBRegisteredDemux); @@ -26,6 +30,14 @@ eDVBAllocatedFrontend::eDVBAllocatedFrontend(eDVBRegisteredFrontend *fe): m_fe(f eDVBAllocatedFrontend::~eDVBAllocatedFrontend() { m_fe->dec_use(); + if (m_fe->m_frontend->is_FBCTuner()) + { + eFBCTunerManager* fbcmng = eFBCTunerManager::getInstance(); + if (fbcmng) + { + fbcmng->unLink(m_fe); + } + } } DEFINE_REF(eDVBAllocatedDemux); @@ -82,6 +94,8 @@ eDVBResourceManager::eDVBResourceManager() num_adapter++; } + setUsbTuner(); + int fd = open("/proc/stb/info/model", O_RDONLY); char tmp[255]; int rd = fd >= 0 ? read(fd, tmp, 255) : 0; @@ -115,6 +129,8 @@ eDVBResourceManager::eDVBResourceManager() eDVBCAService::registerChannelCallback(this); + m_fbc_mng = new eFBCTunerManager(this); + CONNECT(m_releaseCachedChannelTimer->timeout, eDVBResourceManager::releaseCachedChannel); } @@ -138,26 +154,23 @@ eDVBAdapterLinux::eDVBAdapterLinux(int nr): m_nr(nr) { struct stat s; char filename[128]; -#if HAVE_DVB_API_VERSION < 3 - sprintf(filename, "/dev/dvb/card%d/frontend%d", m_nr, num_fe); -#else sprintf(filename, "/dev/dvb/adapter%d/frontend%d", m_nr, num_fe); -#endif if (stat(filename, &s)) break; - ePtr fe; + eDVBFrontend *fe; { int ok = 0; - fe = new eDVBFrontend(m_nr, num_fe, ok); + fe = new eDVBFrontend(m_nr, num_fe, ok, true); if (ok) - m_frontend.push_back(fe); + m_simulate_frontend.push_back(ePtr(fe)); } + { int ok = 0; - fe = new eDVBFrontend(m_nr, num_fe, ok, true); + fe = new eDVBFrontend(m_nr, num_fe, ok, false, fe); if (ok) - m_simulate_frontend.push_back(fe); + m_frontend.push_back(ePtr(fe)); } ++num_fe; } @@ -168,11 +181,7 @@ eDVBAdapterLinux::eDVBAdapterLinux(int nr): m_nr(nr) { struct stat s; char filename[128]; -#if HAVE_DVB_API_VERSION < 3 - sprintf(filename, "/dev/dvb/card%d/demux%d", m_nr, num_demux); -#else sprintf(filename, "/dev/dvb/adapter%d/demux%d", m_nr, num_demux); -#endif if (stat(filename, &s)) break; ePtr demux; @@ -232,11 +241,7 @@ int eDVBAdapterLinux::exist(int nr) { struct stat s; char filename[128]; -#if HAVE_DVB_API_VERSION < 3 - sprintf(filename, "/dev/dvb/card%d", nr); -#else sprintf(filename, "/dev/dvb/adapter%d", nr); -#endif if (!stat(filename, &s)) return 1; return 0; @@ -269,14 +274,12 @@ void eDVBResourceManager::addAdapter(iDVBAdapter *adapter) ePtr frontend; if (!adapter->getFrontend(frontend, i)) { - int frontendType=0; - frontend->getFrontendType(frontendType); eDVBRegisteredFrontend *new_fe = new eDVBRegisteredFrontend(frontend, adapter); CONNECT(new_fe->stateChanged, eDVBResourceManager::feStateChanged); m_frontend.push_back(new_fe); frontend->setSEC(m_sec); // we must link all dvb-t frontends ( for active antenna voltage ) - if (frontendType == iDVBFrontend::feTerrestrial) + if (frontend->supportsDeliverySystem(SYS_DVBT, false) || frontend->supportsDeliverySystem(SYS_DVBT2, false)) { if (prev_dvbt_frontend) { @@ -294,14 +297,12 @@ void eDVBResourceManager::addAdapter(iDVBAdapter *adapter) ePtr frontend; if (!adapter->getFrontend(frontend, i, true)) { - int frontendType=0; - frontend->getFrontendType(frontendType); eDVBRegisteredFrontend *new_fe = new eDVBRegisteredFrontend(frontend, adapter); // CONNECT(new_fe->stateChanged, eDVBResourceManager::feStateChanged); m_simulate_frontend.push_back(new_fe); frontend->setSEC(m_sec); // we must link all dvb-t frontends ( for active antenna voltage ) - if (frontendType == iDVBFrontend::feTerrestrial) + if (frontend->supportsDeliverySystem(SYS_DVBT, false) || frontend->supportsDeliverySystem(SYS_DVBT2, false)) { if (prev_dvbt_frontend) { @@ -315,6 +316,59 @@ void eDVBResourceManager::addAdapter(iDVBAdapter *adapter) } +void eDVBResourceManager::setUsbTuner() +{ + std::ifstream in("/proc/bus/nim_sockets"); + std::string line; + + int res = -1; + int fe_idx = -1; + int usbtuner_idx[8] = {0}; + int usbtuner_count = 0; + + if (in.is_open()) + { + while(!in.eof()) + { + getline(in, line); + if ((res = sscanf(line.c_str(), "NIM Socket %d:", &fe_idx)) == 1) + continue; + + if ((fe_idx != -1) && (line.find("\tName: ") == 0) && (line.find("VTUNER") != -1)) + usbtuner_idx[usbtuner_count++] = fe_idx; + } + in.close(); + } + + if (usbtuner_count) + { + for (eSmartPtrList::iterator it(m_frontend.begin()); it != m_frontend.end(); ++it) + { + int slotid = it->m_frontend->getSlotID(); + for (int i=0; i < usbtuner_count ; i++) + { + if (slotid == usbtuner_idx[i]) + { + it->m_frontend->setUSBTuner(true); + break; + } + } + } + for (eSmartPtrList::iterator it(m_simulate_frontend.begin()); it != m_simulate_frontend.end(); ++it) + { + int slotid = it->m_frontend->getSlotID(); + for (int i=0; i < usbtuner_count ; i++) + { + if (slotid == usbtuner_idx[i]) + { + it->m_frontend->setUSBTuner(true); + break; + } + } + } + } +} + PyObject *eDVBResourceManager::setFrontendSlotInformations(ePyObject list) { if (!PyList_Check(list)) @@ -354,35 +408,139 @@ PyObject *eDVBResourceManager::setFrontendSlotInformations(ePyObject list) Py_RETURN_NONE; } +bool eDVBResourceManager::frontendIsCompatible(int index, const char *type) +{ + for (eSmartPtrList::iterator i(m_frontend.begin()); i != m_frontend.end(); ++i) + { + if (i->m_frontend->getSlotID() == index) + { + if (!strcmp(type, "DVB-S2")) + { + return i->m_frontend->supportsDeliverySystem(SYS_DVBS2, false); + } + else if (!strcmp(type, "DVB-S")) + { + return i->m_frontend->supportsDeliverySystem(SYS_DVBS, false); + } + else if (!strcmp(type, "DVB-T2")) + { + return i->m_frontend->supportsDeliverySystem(SYS_DVBT2, false); + } + else if (!strcmp(type, "DVB-T")) + { + return i->m_frontend->supportsDeliverySystem(SYS_DVBT, false); + } + else if (!strcmp(type, "DVB-C")) + { +#if defined SYS_DVBC_ANNEX_A + return i->m_frontend->supportsDeliverySystem(SYS_DVBC_ANNEX_A, false); +#else + return i->m_frontend->supportsDeliverySystem(SYS_DVBC_ANNEX_AC, false); +#endif + } + } + } + return false; +} + +void eDVBResourceManager::setFrontendType(int index, const char *type) +{ + eDebug("[eDVBResourceManager::setFrontendType] index : %d, type : %s", index, type); + + for (eSmartPtrList::iterator i(m_frontend.begin()); i != m_frontend.end(); ++i) + { + if (i->m_frontend->getSlotID() == index) + { + std::vector whitelist; + if (!strcmp(type, "DVB-S2") || !strcmp(type, "DVB-S")) + { + whitelist.push_back(SYS_DVBS); + whitelist.push_back(SYS_DVBS2); + } + else if (!strcmp(type, "DVB-T2") || !strcmp(type, "DVB-T")) + { + whitelist.push_back(SYS_DVBT); + whitelist.push_back(SYS_DVBT2); + } + else if (!strcmp(type, "DVB-C")) + { +#if defined SYS_DVBC_ANNEX_A + whitelist.push_back(SYS_DVBC_ANNEX_A); +#else + whitelist.push_back(SYS_DVBC_ANNEX_AC); +#endif + } + i->m_frontend->setDeliverySystemWhitelist(whitelist); + break; + } + } +} + RESULT eDVBResourceManager::allocateFrontend(ePtr &fe, ePtr &feparm, bool simulate) { eSmartPtrList &frontends = simulate ? m_simulate_frontend : m_frontend; - ePtr best; + eDVBRegisteredFrontend *best = NULL; int bestval = 0; int foundone = 0; + int check_fbc_leaf_linkable = 0; + int current_fbc_setid = -1; + eDVBRegisteredFrontend *fbc_fe = NULL; + eDVBRegisteredFrontend *best_fbc_fe = NULL; + for (eSmartPtrList::iterator i(frontends.begin()); i != frontends.end(); ++i) { - int c = i->m_frontend->isCompatibleWith(feparm); + int c = 0; + fbc_fe = NULL; + if (i->m_frontend->is_FBCTuner() && m_fbc_mng->canLink(*i)) + { + int fbc_setid = m_fbc_mng->getFBCSetID(i->m_frontend->getSlotID()); + if (fbc_setid != current_fbc_setid) + { + current_fbc_setid = fbc_setid; + check_fbc_leaf_linkable = 0; + } + + if (!check_fbc_leaf_linkable) + { + c = m_fbc_mng->isCompatibleWith(feparm, *i, fbc_fe, simulate); + check_fbc_leaf_linkable = 1; + eDebug("[eDVBResourceManager::allocateFrontend] m_fbc_mng->isCompatibleWith slotid : %p (%d), fbc_fe : %p (%d), score : %d", (eDVBRegisteredFrontend *)*i, i->m_frontend->getSlotID(), fbc_fe, fbc_fe?fbc_fe->m_frontend->getSlotID():-1, c); + } + } + else + { + c = i->m_frontend->isCompatibleWith(feparm); + } if (c) /* if we have at least one frontend which is compatible with the source, flag this. */ foundone = 1; if (!i->m_inuse) { -// eDebug("Slot %d, score %d", i->m_frontend->getSlotID(), c); + eDebug("Slot %d, score %d", i->m_frontend->getSlotID(), c); if (c > bestval) { bestval = c; - best = i; + best = *i; + best_fbc_fe = fbc_fe; } } -// else -// eDebug("Slot %d, score %d... but BUSY!!!!!!!!!!!", i->m_frontend->getSlotID(), c); + else + { + eDebug("Slot %d, score %d... but BUSY!!!!!!!!!!!", i->m_frontend->getSlotID(), c); + } + + eDVBRegisteredFrontend *tmp = *i; } if (best) { + if (best_fbc_fe) + { + m_fbc_mng->addLink(best, best_fbc_fe, simulate); + } + fe = new eDVBAllocatedFrontend(best); return 0; } @@ -524,30 +682,46 @@ RESULT eDVBResourceManager::allocateDemux(eDVBRegisteredFrontend *fe, ePtrm_adapter : m_adapter.begin(); /* look for a demux on the same adapter as the frontend, or the first adapter for dvr playback */ + int source = fe ? fe->m_frontend->getDVBID() : -1; cap |= capHoldDecodeReference; // this is checked in eDVBChannel::getDemux - for (; i != m_demux.end(); ++i, ++n) + if (!fe) { - if (fe) + /* + * For pvr playback, start with the last demux. + * On some hardware, we have less ca devices than demuxes, + * so we should try to leave the first demuxes for live tv, + * and start with the last for pvr playback + */ + i = m_demux.end(); + --i; + } + while (i != m_demux.end()) + { + if (i->m_adapter == adapter) { if (!i->m_inuse) { - if (!unused) - unused = i; + /* mark the first unused demux, we'll use that when we do not find a better match */ + if (!unused) unused = i; } - else if (i->m_adapter == fe->m_adapter && - i->m_demux->getSource() == fe->m_frontend->getDVBID()) + else { - demux = new eDVBAllocatedDemux(i); - return 0; + /* demux is in use, see if we can share it */ + if (source >= 0 && i->m_demux->getSource() == source) + { + demux = new eDVBAllocatedDemux(i); + return 0; + } } } - else if (n == 4) // always use demux4 for PVR (demux 4 can not descramble...) + if (fe) { - if (i->m_inuse) { - demux = new eDVBAllocatedDemux(i); - return 0; - } - unused = i; + ++i; + } + else + { + --i; } } } @@ -586,12 +760,6 @@ RESULT eDVBResourceManager::getChannelList(ePtr &list) if (!simulate) \ eDebug(x); \ } while(0) -// else \ -// { \ -// eDebugNoNewLine("SIMULATE:"); \ -// eDebug(x); \ -// } \ - RESULT eDVBResourceManager::allocateChannel(const eDVBChannelID &channelid, eUsePtr &channel, bool simulate) { @@ -718,8 +886,7 @@ RESULT eDVBResourceManager::allocateRawChannel(eUsePtr &channel, in return 0; } - -RESULT eDVBResourceManager::allocatePVRChannel(eUsePtr &channel) +RESULT eDVBResourceManager::allocatePVRChannel(const eDVBChannelID &channelid, eUsePtr &channel) { ePtr demux; @@ -730,7 +897,18 @@ RESULT eDVBResourceManager::allocatePVRChannel(eUsePtr &channel) m_releaseCachedChannelTimer->stop(); } - channel = new eDVBChannel(this, 0); + ePtr ch = new eDVBChannel(this, 0); + if (channelid) + { + /* + * user provided a channelid, with the clear intention for + * this channel to be registered at the resource manager. + * (allowing e.g. epgcache to be started) + */ + ePtr feparm; + ch->setChannel(channelid, feparm); + } + channel = ch; return 0; } @@ -786,28 +964,52 @@ int eDVBResourceManager::canAllocateFrontend(ePtr &fepar eSmartPtrList &frontends = simulate ? m_simulate_frontend : m_frontend; ePtr best; int bestval = 0; + int check_fbc_leaf_linkable = 0; + int current_fbc_setid = -1; for (eSmartPtrList::iterator i(frontends.begin()); i != frontends.end(); ++i) + { if (!i->m_inuse) { - int c = i->m_frontend->isCompatibleWith(feparm); + int c = 0; + if (i->m_frontend->is_FBCTuner() && m_fbc_mng->canLink(*i)) + { + int fbc_setid = m_fbc_mng->getFBCSetID(i->m_frontend->getSlotID()); + if (fbc_setid != current_fbc_setid) + { + current_fbc_setid = fbc_setid; + check_fbc_leaf_linkable = 0; + } + + if (!check_fbc_leaf_linkable) + { + eDVBRegisteredFrontend *dummy; + c = m_fbc_mng->isCompatibleWith(feparm, *i, dummy, simulate); + check_fbc_leaf_linkable = 1; + } + } + else + { + c = i->m_frontend->isCompatibleWith(feparm); + } if (c > bestval) bestval = c; } + } return bestval; } -int tuner_type_channel_default(ePtr &channellist, const eDVBChannelID &chid) +int tuner_type_channel_default(ePtr &channellist, const eDVBChannelID &chid, int &system) { + system = iDVBFrontend::feSatellite; if (channellist) { ePtr feparm; if (!channellist->getChannelFrontendData(chid, feparm)) { - int system; if (!feparm->getSystem(system)) { - switch(system) + switch (system) { case iDVBFrontend::feSatellite: return 50000; @@ -824,15 +1026,16 @@ int tuner_type_channel_default(ePtr &channellist, const eDVBCha return 0; } -int eDVBResourceManager::canAllocateChannel(const eDVBChannelID &channelid, const eDVBChannelID& ignore, bool simulate) +int eDVBResourceManager::canAllocateChannel(const eDVBChannelID &channelid, const eDVBChannelID& ignore, int &system, bool simulate) { std::list &active_channels = simulate ? m_active_simulate_channels : m_active_channels; - int ret=0; + int ret = 0; + system = iDVBFrontend::feSatellite; if (!simulate && m_cached_channel) { eDVBChannel *cache_chan = (eDVBChannel*)&(*m_cached_channel); if(channelid==cache_chan->getChannelID()) - return tuner_type_channel_default(m_list, channelid); + return tuner_type_channel_default(m_list, channelid, system); } /* first, check if a channel is already existing. */ @@ -843,13 +1046,63 @@ int eDVBResourceManager::canAllocateChannel(const eDVBChannelID &channelid, cons if (i->m_channel_id == channelid) { // eDebug("found shared channel.."); - return tuner_type_channel_default(m_list, channelid); + return tuner_type_channel_default(m_list, channelid, system); } } int *decremented_cached_channel_fe_usecount=NULL, *decremented_fe_usecount=NULL; + /* check FCC channels */ + std::vector fcc_decremented_fe_usecounts; + std::map fcc_chids; + int apply_to_ignore = 0; + if (!eFCCServiceManager::getFCCChannelID(fcc_chids)) + { + for (std::map::iterator i(fcc_chids.begin()); i != fcc_chids.end(); ++i) + { + //eDebug("[eDVBResourceManager::canAllocateChannel] FCC NS : %08x, TSID : %04x, ONID : %04x", i->first.dvbnamespace.get(), i->first.transport_stream_id.get(), i->first.original_network_id.get()); + if (ignore == i->first) + { + apply_to_ignore = i->second; + continue; + } + for (std::list::iterator ii(active_channels.begin()); ii != active_channels.end(); ++ii) + { + eSmartPtrList &frontends = simulate ? m_simulate_frontend : m_frontend; + if (ii->m_channel_id == i->first) + { + eDVBChannel *channel = (eDVBChannel*) &(*ii->m_channel); + + int check_usecount = channel == &(*m_cached_channel) ? 1 : 0; + check_usecount += i->second * 2; // one is used in eDVBServicePMTHandler and another is used in eDVBScan. + //eDebug("[eDVBResourceManager::canAllocateChannel] channel->getUseCount() : %d , check_usecount : %d (cached : %d)", channel->getUseCount(), check_usecount, channel == &(*m_cached_channel)); + if (channel->getUseCount() == check_usecount) + { + ePtr fe; + if (!ii->m_channel->getFrontend(fe)) + { + for (eSmartPtrList::iterator iii(frontends.begin()); iii != frontends.end(); ++iii) + { + if ( &(*fe) == &(*iii->m_frontend) ) + { + //eDebug("[eDVBResourceManager::canAllocateChannel] fcc : decrease fcc fe use_count! feid : %d (%d -> %d)", iii->m_frontend->getSlotID(), iii->m_inuse, iii->m_inuse-1); + --iii->m_inuse; + int *tmp_decremented_fe_usecount = &iii->m_inuse; + fcc_decremented_fe_usecounts.push_back(tmp_decremented_fe_usecount); + if (channel == &(*m_cached_channel)) + decremented_cached_channel_fe_usecount = tmp_decremented_fe_usecount; + break; + } + } + } + } + break; + } + } + } + } + for (std::list::iterator i(active_channels.begin()); i != active_channels.end(); ++i) { eSmartPtrList &frontends = simulate ? m_simulate_frontend : m_frontend; @@ -861,7 +1114,10 @@ int eDVBResourceManager::canAllocateChannel(const eDVBChannelID &channelid, cons // another on eUsePtr is used in the eDVBScan instance used in eDVBServicePMTHandler (for SDT scan) // so we must check here if usecount is 3 (when the channel is equal to the cached channel) // or 2 when the cached channel is not equal to the compared channel - if (channel == &(*m_cached_channel) ? channel->getUseCount() == 3 : channel->getUseCount() == 2) // channel only used once.. + int check_usecount = channel == &(*m_cached_channel) ? 1 : 0; + check_usecount += (apply_to_ignore+1) * 2; // one is used in eDVBServicePMTHandler and another is used in eDVBScan. + //eDebug("[eDVBResourceManager::canAllocateChannel] channel->getUseCount() : %d , check_usecount : %d (cached : %d)", channel->getUseCount(), check_usecount, channel == &(*m_cached_channel)); + if (channel->getUseCount() == check_usecount) // channel only used once..(except fcc) { ePtr fe; if (!i->m_channel->getFrontend(fe)) @@ -870,6 +1126,7 @@ int eDVBResourceManager::canAllocateChannel(const eDVBChannelID &channelid, cons { if ( &(*fe) == &(*ii->m_frontend) ) { + //eDebug("[eDVBResourceManager::canAllocateChannel] ignore : decrease fcc fe use_count! feid : %d (%d -> %d)", ii->m_frontend->getSlotID(), ii->m_inuse, ii->m_inuse-1); --ii->m_inuse; decremented_fe_usecount = &ii->m_inuse; if (channel == &(*m_cached_channel)) @@ -923,6 +1180,7 @@ int eDVBResourceManager::canAllocateChannel(const eDVBChannelID &channelid, cons eDebug("channel not found!"); goto error; } + feparm->getSystem(system); ret = canAllocateFrontend(feparm, simulate); @@ -931,6 +1189,14 @@ error: ++(*decremented_fe_usecount); if (decremented_cached_channel_fe_usecount) ++(*decremented_cached_channel_fe_usecount); + if (fcc_decremented_fe_usecounts.size()) + { + for (std::vector::iterator i(fcc_decremented_fe_usecounts.begin()); i != fcc_decremented_fe_usecounts.end(); ++i) + { + //eDebug("[eDVBResourceManager::canAllocateChannel] fcc : increase fcc fe use_count!"); + ++(**i); + } + } return ret; } @@ -1186,8 +1452,22 @@ void eDVBChannel::frontendStateChanged(iDVBFrontend*fe) } } else if (state == iDVBFrontend::stateFailed) { +#ifdef BUILD_VUPLUS + if (m_current_frontend_parameters) + { + eDebug("OURSTATE: lost lock, trying to retune"); + ourstate = state_tuning; + m_frontend->get().tune(*m_current_frontend_parameters); + } + else + { + eDebug("OURSTATE: failed"); + ourstate = state_failed; + } +#else eDebug("OURSTATE: failed"); ourstate = state_failed; +#endif } else eFatal("state unknown"); @@ -1210,6 +1490,10 @@ void eDVBChannel::pvrEvent(int event) eDebug("SOF"); m_event(this, evtSOF); break; + case eFilePushThread::evtUser+3: /* limit space */ + eDebug("Too large file"); + m_event(this, evtFailed+3); + break; } } @@ -1311,8 +1595,9 @@ static inline long long align_with_len(long long x, int align, size_t &len) if (sign) x = -x; - x -= x % align; - len += x % align; + int r = x % align; + x -= r; + len += r; if (sign) x = -x; @@ -1341,13 +1626,13 @@ void eDVBChannel::getNextSourceSpan(off_t current_offset, size_t bytes_read, off max = align(m_skipmode_n, blocksize); } - eDebug("getNextSourceSpan, current offset is %08llx, m_skipmode_m = %d!", current_offset, m_skipmode_m); + eDebug("getNextSourceSpan, current offset is %08lld, m_skipmode_m = %d!", current_offset, m_skipmode_m); int frame_skip_success = 0; if (m_skipmode_m) { int frames_to_skip = m_skipmode_frames + m_skipmode_frames_remainder; - eDebug("we are at %llx, and we try to skip %d+%d frames from here", current_offset, m_skipmode_frames, m_skipmode_frames_remainder); + eDebug("we are at %lld, and we try to skip %d+%d frames from here", current_offset, m_skipmode_frames, m_skipmode_frames_remainder); size_t iframe_len; off_t iframe_start = current_offset; int frames_skipped = frames_to_skip; @@ -1368,20 +1653,24 @@ void eDVBChannel::getNextSourceSpan(off_t current_offset, size_t bytes_read, off if (!frame_skip_success) { current_offset += align(m_skipmode_m, blocksize); - - if (m_skipmode_m) + if(current_offset < 0) + current_offset = 0; + else { - eDebug("we are at %llx, and we try to find the iframe here:", current_offset); - size_t iframe_len; - off_t iframe_start = current_offset; - - int direction = (m_skipmode_m < 0) ? -1 : +1; - if (m_tstools.findFrame(iframe_start, iframe_len, direction)) - eDebug("failed"); - else + if (m_skipmode_m) { - current_offset = align_with_len(iframe_start, blocksize, iframe_len); - max = align(iframe_len, blocksize); + eDebug("we are at %lld, and we try to find the iframe here:", current_offset); + size_t iframe_len; + off_t start_offset = current_offset; + off_t new_offset = start_offset; + int direction = (m_skipmode_m < 0) ? -1 : +1; + if (m_tstools.findFrame(start_offset, new_offset, iframe_len, direction)) + eDebug("failed"); + else + { + current_offset = align_with_len(new_offset, blocksize, iframe_len); + max = align(iframe_len, blocksize); + } } } } @@ -1539,18 +1828,19 @@ void eDVBChannel::getNextSourceSpan(off_t current_offset, size_t bytes_read, off } } + if(current_offset <0) + current_offset =0; if ((current_offset < -m_skipmode_m) && (m_skipmode_m < 0)) { eDebug("reached SOF"); m_skipmode_m = 0; m_pvr_thread->sendEvent(eFilePushThread::evtUser); } - if (m_source_span.empty()) { start = current_offset; size = max; - eDebug("NO CUESHEET. (%08llx, %zd)", start, size); + eDebug("NO CUESHEET. (%08lld, %zd)", start, size); } else { start = current_offset; @@ -1590,14 +1880,15 @@ RESULT eDVBChannel::setChannel(const eDVBChannelID &channelid, ePtraddChannel(channelid, this); + if (!m_frontend) { - eDebug("no frontend to tune!"); - return -ENODEV; + /* no frontend, no need to tune (must be a streamed service) */ + return 0; } - m_channel_id = channelid; - m_mgr->addChannel(channelid, this); m_state = state_tuning; /* if tuning fails, shutdown the channel immediately. */ int res; @@ -1708,6 +1999,12 @@ RESULT eDVBChannel::getDemux(ePtr &demux, int cap) { ePtr &our_demux = (cap & capDecode) ? m_decoder_demux : m_demux; + if (m_frontend == NULL) + { + /* in dvr mode, we have to stick to a single demux (the one connected to our dvr device) */ + our_demux = m_decoder_demux ? m_decoder_demux : m_demux; + } + if (!our_demux) { demux = 0; @@ -1776,13 +2073,14 @@ RESULT eDVBChannel::playSource(ePtr &source, const char *streaminfo_f m_pvr_thread = 0; } - if (!source->valid()) + if (!source->valid() && !source->isStream()) { eDebug("PVR source is not valid!"); return -ENOENT; } - m_tstools.setSource(source, streaminfo_file); + m_source = source; + m_tstools.setSource(m_source, streaminfo_file); /* DON'T EVEN THINK ABOUT FIXING THIS. FIX THE ATI SOURCES FIRST, THEN DO A REAL FIX HERE! */ @@ -1790,14 +2088,6 @@ RESULT eDVBChannel::playSource(ePtr &source, const char *streaminfo_f if (m_pvr_fd_dst < 0) { /* (this codepath needs to be improved anyway.) */ -#if HAVE_DVB_API_VERSION < 3 - m_pvr_fd_dst = open("/dev/pvr", O_WRONLY); - if (m_pvr_fd_dst < 0) - { - eDebug("can't open /dev/pvr - you need to buy the new(!) $$$ box! (%m)"); // or wait for the driver to be improved. - return -ENODEV; - } -#else ePtr &demux = m_demux ? m_demux : m_decoder_demux; if (demux) { @@ -1813,17 +2103,17 @@ RESULT eDVBChannel::playSource(ePtr &source, const char *streaminfo_f eDebug("no demux allocated yet.. so its not possible to open the dvr device!!"); return -ENODEV; } -#endif } m_pvr_thread = new eDVBChannelFilePush(); m_pvr_thread->enablePVRCommit(1); - m_pvr_thread->setStreamMode(1); + /* If the source specifies a length, it's a file. If not, it's a stream */ + m_pvr_thread->setStreamMode(m_source->isStream()); m_pvr_thread->setScatterGather(this); m_event(this, evtPreStart); - m_pvr_thread->start(source, m_pvr_fd_dst); + m_pvr_thread->start(m_source, m_pvr_fd_dst); CONNECT(m_pvr_thread->m_event, eDVBChannel::pvrEvent); m_state = state_ok; @@ -1841,9 +2131,13 @@ void eDVBChannel::stopSource() m_pvr_thread = 0; } if (m_pvr_fd_dst >= 0) + { ::close(m_pvr_fd_dst); - ePtr d; - m_tstools.setSource(d); + m_pvr_fd_dst = -1; + } + + m_source = NULL; + m_tstools.setSource(m_source); } void eDVBChannel::stopFile() @@ -1884,8 +2178,7 @@ RESULT eDVBChannel::getCurrentPosition(iDVBDemux *decoding_demux, pts_t &pos, in } else now = pos; /* fixup supplied */ - off_t off = 0; /* TODO: fixme */ - r = m_tstools.fixupPTS(off, now); + r = m_tstools.fixupPTS(m_source ? m_source->offset() : 0, now); if (r) { eDebug("fixup PTS failed");