X-Git-Url: https://git.cweiske.de/enigma2.git/blobdiff_plain/fd9ebe13e2e86c7fb3a80769e419538e1cfe9142..f97a4e53dcd9321cfe4d026f8efac3a3fea1cb6a:/lib/dvb/dvb.cpp diff --git a/lib/dvb/dvb.cpp b/lib/dvb/dvb.cpp index 03c2aab6..41c4f3ca 100644 --- a/lib/dvb/dvb.cpp +++ b/lib/dvb/dvb.cpp @@ -242,8 +242,8 @@ void eDVBResourceManager::addAdapter(iDVBAdapter *adapter) { if (prev_dvbt_frontend) { - prev_dvbt_frontend->m_frontend->setData(eDVBFrontend::LINKED_NEXT_PTR, (int)new_fe); - frontend->setData(eDVBFrontend::LINKED_PREV_PTR, (int)&(*prev_dvbt_frontend)); + prev_dvbt_frontend->m_frontend->setData(eDVBFrontend::LINKED_NEXT_PTR, (long)new_fe); + frontend->setData(eDVBFrontend::LINKED_PREV_PTR, (long)&(*prev_dvbt_frontend)); } prev_dvbt_frontend = new_fe; } @@ -280,42 +280,54 @@ RESULT eDVBResourceManager::allocateFrontend(ePtr &fe, eP { ePtr best; int bestval = 0; + int foundone = 0; for (eSmartPtrList::iterator i(m_frontend.begin()); i != m_frontend.end(); ++i) + { + int 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) { - int c = i->m_frontend->isCompatibleWith(feparm); if (c > bestval) { bestval = c; best = i; } } + } if (best) { fe = new eDVBAllocatedFrontend(best); return 0; } - + fe = 0; - - return -1; + + if (foundone) + return errAllSourcesBusy; + else + return errNoSourceFound; } RESULT eDVBResourceManager::allocateFrontendByIndex(ePtr &fe, int slot_index) { + int err = errNoSourceFound; for (eSmartPtrList::iterator i(m_frontend.begin()); i != m_frontend.end(); ++i) if (!i->m_inuse && i->m_frontend->getSlotID() == slot_index) { // check if another slot linked to this is in use eDVBRegisteredFrontend *satpos_depends_to_fe = (eDVBRegisteredFrontend*) i->m_frontend->m_data[eDVBFrontend::SATPOS_DEPENDS_PTR]; - if ( (int)satpos_depends_to_fe != -1 ) + if ( (long)satpos_depends_to_fe != -1 ) { if (satpos_depends_to_fe->m_inuse) { eDebug("another satpos depending frontend is in use.. so allocateFrontendByIndex not possible!"); + err = errAllSourcesBusy; goto alloc_fe_by_id_not_possible; } } @@ -323,22 +335,24 @@ RESULT eDVBResourceManager::allocateFrontendByIndex(ePtr { eDVBRegisteredFrontend *next = (eDVBRegisteredFrontend *) i->m_frontend->m_data[eDVBFrontend::LINKED_NEXT_PTR]; - while ( (int)next != -1 ) + while ( (long)next != -1 ) { if (next->m_inuse) { eDebug("another linked frontend is in use.. so allocateFrontendByIndex not possible!"); + err = errAllSourcesBusy; goto alloc_fe_by_id_not_possible; } next = (eDVBRegisteredFrontend *)next->m_frontend->m_data[eDVBFrontend::LINKED_NEXT_PTR]; } eDVBRegisteredFrontend *prev = (eDVBRegisteredFrontend *) i->m_frontend->m_data[eDVBFrontend::LINKED_PREV_PTR]; - while ( (int)prev != -1 ) + while ( (long)prev != -1 ) { if (prev->m_inuse) { eDebug("another linked frontend is in use.. so allocateFrontendByIndex not possible!"); + err = errAllSourcesBusy; goto alloc_fe_by_id_not_possible; } prev = (eDVBRegisteredFrontend *)prev->m_frontend->m_data[eDVBFrontend::LINKED_PREV_PTR]; @@ -349,7 +363,7 @@ RESULT eDVBResourceManager::allocateFrontendByIndex(ePtr } alloc_fe_by_id_not_possible: fe = 0; - return -1; + return err; } RESULT eDVBResourceManager::allocateDemux(eDVBRegisteredFrontend *fe, ePtr &demux, int cap) @@ -447,22 +461,23 @@ RESULT eDVBResourceManager::allocateChannel(const eDVBChannelID &channelid, eUse if (!m_list) { eDebug("no channel list set!"); - return -ENOENT; + return errNoChannelList; } ePtr feparm; if (m_list->getChannelFrontendData(channelid, feparm)) { eDebug("channel not found!"); - return -ENOENT; + return errChannelNotInList; } /* allocate a frontend. */ ePtr fe; - - if (allocateFrontend(fe, feparm)) - return errNoFrontend; + + int err = allocateFrontend(fe, feparm); + if (err) + return err; RESULT res; ePtr ch; @@ -522,9 +537,10 @@ RESULT eDVBResourceManager::allocateRawChannel(eUsePtr &channel, in m_releaseCachedChannelTimer.stop(); } - if (allocateFrontendByIndex(fe, slot_index)) - return errNoFrontend; - + int err = allocateFrontendByIndex(fe, slot_index); + if (err) + return err; + eDVBChannel *ch; ch = new eDVBChannel(this, fe); @@ -597,14 +613,41 @@ int eDVBResourceManager::canAllocateFrontend(ePtr &fepar return bestval; } +int tuner_type_channel_default(ePtr &channellist, const eDVBChannelID &chid) +{ + if (channellist) + { + ePtr feparm; + if (!channellist->getChannelFrontendData(chid, feparm)) + { + int system; + if (!feparm->getSystem(system)) + { + switch(system) + { + case iDVBFrontend::feSatellite: + return 50000; + case iDVBFrontend::feCable: + return 40000; + case iDVBFrontend::feTerrestrial: + return 30000; + default: + break; + } + } + } + } + return 0; +} + int eDVBResourceManager::canAllocateChannel(const eDVBChannelID &channelid, const eDVBChannelID& ignore) { - int ret=30000; + int ret=0; if (m_cached_channel) { eDVBChannel *cache_chan = (eDVBChannel*)&(*m_cached_channel); if(channelid==cache_chan->getChannelID()) - return ret; + return tuner_type_channel_default(m_list, channelid); } /* first, check if a channel is already existing. */ @@ -615,7 +658,7 @@ int eDVBResourceManager::canAllocateChannel(const eDVBChannelID &channelid, cons if (i->m_channel_id == channelid) { // eDebug("found shared channel.."); - return ret; + return tuner_type_channel_default(m_list, channelid); } } @@ -685,14 +728,12 @@ int eDVBResourceManager::canAllocateChannel(const eDVBChannelID &channelid, cons if (!m_list) { eDebug("no channel list set!"); - ret = 0; goto error; } if (m_list->getChannelFrontendData(channelid, feparm)) { eDebug("channel not found!"); - ret = 0; goto error; } @@ -707,24 +748,119 @@ error: return ret; } +bool eDVBResourceManager::canMeasureFrontendInputPower() +{ + for (eSmartPtrList::iterator i(m_frontend.begin()); i != m_frontend.end(); ++i) + { + return i->m_frontend->readInputpower() >= 0; + } + return false; +} + class eDVBChannelFilePush: public eFilePushThread { public: + eDVBChannelFilePush() { setIFrameSearch(0); setTimebaseChange(0); } void setIFrameSearch(int enabled) { m_iframe_search = enabled; m_iframe_state = 0; } + + /* "timebase change" is for doing trickmode playback at an exact speed, even when pictures are skipped. */ + /* you need to set it to 1/16 if you want 16x playback, for example. you need video master sync. */ + void setTimebaseChange(int ratio) { m_timebase_change = ratio; } /* 16bit fixpoint, 0 for disable */ protected: int m_iframe_search, m_iframe_state, m_pid; + int m_timebase_change; int filterRecordData(const unsigned char *data, int len, size_t ¤t_span_remaining); }; int eDVBChannelFilePush::filterRecordData(const unsigned char *_data, int len, size_t ¤t_span_remaining) { -#if 0 /* not yet */ +#if 0 + if (m_timebase_change) + { + eDebug("timebase change: %d", m_timebase_change); + int offset; + for (offset = 0; offset < len; offset += 188) + { + unsigned char *pkt = (unsigned char*)_data + offset; + if (pkt[1] & 0x40) /* pusi */ + { + if (pkt[3] & 0x20) // adaption field present? + pkt += pkt[4] + 4 + 1; /* skip adaption field and header */ + else + pkt += 4; /* skip header */ + if (pkt[0] || pkt[1] || (pkt[2] != 1)) + { + eWarning("broken startcode"); + continue; + } + + pts_t pts = 0; + + if (pkt[7] & 0x80) // PTS present? + { + pts = ((unsigned long long)(pkt[ 9]&0xE)) << 29; + pts |= ((unsigned long long)(pkt[10]&0xFF)) << 22; + pts |= ((unsigned long long)(pkt[11]&0xFE)) << 14; + pts |= ((unsigned long long)(pkt[12]&0xFF)) << 7; + pts |= ((unsigned long long)(pkt[13]&0xFE)) >> 1; + +#if 0 + off_t off = 0; + RESULT r = m_tstools.fixupPTS(off, pts); + if (r) + eWarning("fixup PTS while trickmode playback failed.\n"); +#endif + + int sec = pts / 90000; + int frm = pts % 90000; + int min = sec / 60; + sec %= 60; + int hr = min / 60; + min %= 60; + int d = hr / 24; + hr %= 24; + +// eDebug("original, fixed pts: %016llx %d:%02d:%02d:%02d:%05d", pts, d, hr, min, sec, frm); + + pts += 0x80000000LL; + pts *= m_timebase_change; + pts >>= 16; + + sec = pts / 90000; + frm = pts % 90000; + min = sec / 60; + sec %= 60; + hr = min / 60; + min %= 60; + d = hr / 24; + hr %= 24; + +// eDebug("new pts (after timebase change): %016llx %d:%02d:%02d:%02d:%05d", pts, d, hr, min, sec, frm); + + pkt[9] &= ~0xE; + pkt[10] = 0; + pkt[11] &= ~1; + pkt[12] = 0; + pkt[13] &= ~1; + + pkt[9] |= (pts >> 29) & 0xE; + pkt[10] |= (pts >> 22) & 0xFF; + pkt[11] |= (pts >> 14) & 0xFE; + pkt[12] |= (pts >> 7) & 0xFF; + pkt[13] |= (pts << 1) & 0xFE; + } + } + } + } +#endif + +#if 1 /* not yet */ if (!m_iframe_search) return len; unsigned char *data = (unsigned char*)_data; /* remove that const. we know what we are doing. */ - eDebug("filterRecordData, size=%d (mod 188=%d), first byte is %02x", len, len %188, data[0]); +// eDebug("filterRecordData, size=%d (mod 188=%d), first byte is %02x", len, len %188, data[0]); unsigned char *d = data; while ((d = (unsigned char*)memmem(d, data + len - d, "\x00\x00\x01", 3))) @@ -738,8 +874,8 @@ int eDVBChannelFilePush::filterRecordData(const unsigned char *_data, int len, s { int picture_type = (d[5] >> 3) & 7; d += 4; - - eDebug("%d-frame at %d, offset in TS packet: %d, pid=%04x", picture_type, offset, offset % 188, pid); + +// eDebug("%d-frame at %d, offset in TS packet: %d, pid=%04x", picture_type, offset, offset % 188, pid); if (m_iframe_state == 1) { @@ -761,19 +897,19 @@ int eDVBChannelFilePush::filterRecordData(const unsigned char *_data, int len, s { if (picture_type != 1) /* we are only interested in I frames */ continue; - + unsigned char *fts = data; while (fts < ts) { fts[1] |= 0x1f; fts[2] |= 0xff; /* drop packet */ - + fts += 188; } /* force payload only */ ts[3] &= ~0x30; ts[3] |= 0x10; - + // memset(ts + 4, 0xFF, (offset % 188) - 4); m_iframe_state = 1; @@ -907,18 +1043,17 @@ void eDVBChannel::cueSheetEvent(int event) /* i agree that this might look a bit like black magic. */ m_skipmode_n = 512*1024; /* must be 1 iframe at least. */ m_skipmode_m = bitrate / 8 / 90000 * m_cue->m_skipmode_ratio / 8; - + if (m_cue->m_skipmode_ratio < 0) m_skipmode_m -= m_skipmode_n; - + eDebug("resolved to: %d %d", m_skipmode_m, m_skipmode_n); - + if (abs(m_skipmode_m) < abs(m_skipmode_n)) { eWarning("something is wrong with this calculation"); m_skipmode_n = m_skipmode_m = 0; } - } else { eDebug("skipmode ratio is 0, normal play"); @@ -927,6 +1062,10 @@ void eDVBChannel::cueSheetEvent(int event) } ASSERT(m_pvr_thread); m_pvr_thread->setIFrameSearch(m_skipmode_n != 0); + if (m_cue->m_skipmode_ratio != 0) + m_pvr_thread->setTimebaseChange(0x10000 * 9000 / (m_cue->m_skipmode_ratio / 10)); /* negative values are also ok */ + else + m_pvr_thread->setTimebaseChange(0); /* normal playback */ eDebug("flush pvr"); flushPVR(m_cue->m_decoding_demux); eDebug("done"); @@ -1436,6 +1575,7 @@ void eCueSheet::clear() void eCueSheet::addSourceSpan(const pts_t &begin, const pts_t &end) { + assert(begin < end); m_lock.WrLock(); m_spans.push_back(std::pair(begin, end)); m_lock.Unlock();