X-Git-Url: https://git.cweiske.de/enigma2.git/blobdiff_plain/bce53d4a67d1655a496eebe5912c8573e880114e..37152843c915fd0a9352256d804ced4ff54c23c4:/lib/dvb/dvb.cpp diff --git a/lib/dvb/dvb.cpp b/lib/dvb/dvb.cpp index 1c4eef8a..40d44186 100644 --- a/lib/dvb/dvb.cpp +++ b/lib/dvb/dvb.cpp @@ -82,8 +82,34 @@ eDVBResourceManager::eDVBResourceManager() num_adapter++; } - eDebug("found %d adapter, %d frontends(%d sim) and %d demux", - m_adapter.size(), m_frontend.size(), m_simulate_frontend.size(), m_demux.size()); + int fd = open("/proc/stb/info/model", O_RDONLY); + char tmp[255]; + int rd = fd >= 0 ? read(fd, tmp, 255) : 0; + if (fd >= 0) + close(fd); + + if (!strncmp(tmp, "dm7025\n", rd)) + m_boxtype = DM7025; + else if (!strncmp(tmp, "dm8000\n", rd)) + m_boxtype = DM8000; + else if (!strncmp(tmp, "dm800\n", rd)) + m_boxtype = DM800; + else if (!strncmp(tmp, "dm500hd\n", rd)) + m_boxtype = DM500HD; + else if (!strncmp(tmp, "dm800se\n", rd)) + m_boxtype = DM800SE; + else { + eDebug("boxtype detection via /proc/stb/info not possible... use fallback via demux count!\n"); + if (m_demux.size() == 3) + m_boxtype = DM800; + else if (m_demux.size() < 5) + m_boxtype = DM7025; + else + m_boxtype = DM8000; + } + + eDebug("found %d adapter, %d frontends(%d sim) and %d demux, boxtype %d", + m_adapter.size(), m_frontend.size(), m_simulate_frontend.size(), m_demux.size(), m_boxtype); eDVBCAService::registerChannelCallback(this); @@ -414,7 +440,9 @@ alloc_fe_by_id_not_possible: return err; } -RESULT eDVBResourceManager::allocateDemux(eDVBRegisteredFrontend *fe, ePtr &demux, int cap) +#define capHoldDecodeReference 64 + +RESULT eDVBResourceManager::allocateDemux(eDVBRegisteredFrontend *fe, ePtr &demux, int &cap) { /* find first unused demux which is on same adapter as frontend (or any, if PVR) never use the first one unless we need a decoding demux. */ @@ -429,7 +457,36 @@ RESULT eDVBResourceManager::allocateDemux(eDVBRegisteredFrontend *fe, ePtr unused; - if (m_demux.size() < 5) + if (m_boxtype == DM800 || m_boxtype == DM500HD || m_boxtype == DM800SE) // dm800 / 500hd + { + cap |= capHoldDecodeReference; // this is checked in eDVBChannel::getDemux + for (; i != m_demux.end(); ++i, ++n) + { + if (!i->m_inuse) + { + if (!unused) + unused = i; + } + else + { + if (fe) + { + if (i->m_adapter == fe->m_adapter && + i->m_demux->getSource() == fe->m_frontend->getDVBID()) + { + demux = new eDVBAllocatedDemux(i); + return 0; + } + } + else if (i->m_demux->getSource() == -1) // PVR + { + demux = new eDVBAllocatedDemux(i); + return 0; + } + } + } + } + else if (m_boxtype == DM7025) // ATI { /* FIXME: hardware demux policy */ if (!(cap & iDVBChannel::capDecode)) @@ -456,8 +513,9 @@ RESULT eDVBResourceManager::allocateDemux(eDVBRegisteredFrontend *fe, ePtrget().connectStateChange(slot(*this, &eDVBChannel::frontendStateChanged), m_conn_frontendStateChanged); @@ -1170,6 +1229,8 @@ 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; + m_skipmode_frames = m_cue->m_skipmode_ratio / 90000; + m_skipmode_frames_remainder = 0; if (m_cue->m_skipmode_ratio < 0) m_skipmode_m -= m_skipmode_n; @@ -1179,12 +1240,12 @@ void eDVBChannel::cueSheetEvent(int event) if (abs(m_skipmode_m) < abs(m_skipmode_n)) { eWarning("something is wrong with this calculation"); - m_skipmode_n = m_skipmode_m = 0; + m_skipmode_frames = m_skipmode_n = m_skipmode_m = 0; } } else { eDebug("skipmode ratio is 0, normal play"); - m_skipmode_n = m_skipmode_m = 0; + m_skipmode_frames = m_skipmode_n = m_skipmode_m = 0; } } m_pvr_thread->setIFrameSearch(m_skipmode_n != 0); @@ -1227,6 +1288,23 @@ static inline long long align(long long x, int align) x -= x % align; + if (sign) + x = -x; + + return x; +} + + /* align toward zero */ +static inline long long align_with_len(long long x, int align, size_t &len) +{ + int sign = x < 0; + + if (sign) + x = -x; + + x -= x % align; + len += x % align; + if (sign) x = -x; @@ -1248,41 +1326,59 @@ void eDVBChannel::getNextSourceSpan(off_t current_offset, size_t bytes_read, off return; } - m_cue->m_lock.RdLock(); - if (!m_cue->m_decoding_demux) - { - start = current_offset; - size = max; - eDebug("getNextSourceSpan, no decoding demux. forcing normal play"); - m_cue->m_lock.Unlock(); - return; - } - if (m_skipmode_n) { - eDebug("skipmode %d:%d", m_skipmode_m, m_skipmode_n); + eDebug("skipmode %d:%d (x%d)", m_skipmode_m, m_skipmode_n, m_skipmode_frames); max = align(m_skipmode_n, blocksize); } eDebug("getNextSourceSpan, current offset is %08llx, m_skipmode_m = %d!", current_offset, m_skipmode_m); + int frame_skip_success = 0; - current_offset += align(m_skipmode_m, blocksize); - if (m_skipmode_m) { - eDebug("we are at %llx, and we try to find the iframe here:", current_offset); + 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); size_t iframe_len; off_t iframe_start = current_offset; + int frames_skipped = frames_to_skip; + if (!m_tstools.findNextPicture(iframe_start, iframe_len, frames_skipped)) + { + m_skipmode_frames_remainder = frames_to_skip - frames_skipped; + eDebug("successfully skipped %d (out of %d, rem now %d) frames.", frames_skipped, frames_to_skip, m_skipmode_frames_remainder); + current_offset = align_with_len(iframe_start, blocksize, iframe_len); + max = align(iframe_len + 187, blocksize); + frame_skip_success = 1; + } else + { + m_skipmode_frames_remainder = 0; + eDebug("frame skipping failed, reverting to byte-skipping"); + } + } + + if (!frame_skip_success) + { + current_offset += align(m_skipmode_m, blocksize); - if (m_tstools.findIFrame(iframe_start, iframe_len, (m_skipmode_m < 0) ? -1 : +1)) - eDebug("failed"); - else + if (m_skipmode_m) { - current_offset = align(iframe_start, blocksize); - max = align(iframe_len, blocksize); + 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 + { + current_offset = align_with_len(iframe_start, blocksize, iframe_len); + max = align(iframe_len, blocksize); + } } } + m_cue->m_lock.RdLock(); + while (!m_cue->m_seek_requests.empty()) { std::pair seek = m_cue->m_seek_requests.front(); @@ -1307,6 +1403,13 @@ void eDVBChannel::getNextSourceSpan(off_t current_offset, size_t bytes_read, off eDebug("decoder getPTS failed, can't seek relative"); continue; } + if (!m_cue->m_decoding_demux) + { + eDebug("getNextSourceSpan, no decoding demux. couldn't seek to %llx... ignore request!", pts); + start = current_offset; + size = max; + continue; + } if (getCurrentPosition(m_cue->m_decoding_demux, now, 1)) { eDebug("seekTo: getCurrentPosition failed!"); @@ -1359,10 +1462,6 @@ void eDVBChannel::getNextSourceSpan(off_t current_offset, size_t bytes_read, off continue; } - size_t iframe_len; - /* try to align to iframe */ - m_tstools.findIFrame(offset, iframe_len, pts < 0 ? -1 : 1); - eDebug("ok, resolved skip (rel: %d, diff %lld), now at %08llx", relative, pts, offset); current_offset = align(offset, blocksize); /* in case tstools return non-aligned offset */ } @@ -1560,6 +1659,18 @@ void eDVBChannel::SDTready(int result) m_SDT = 0; } +int eDVBChannel::reserveDemux() +{ + ePtr dmx; + if (!getDemux(dmx, 0)) + { + uint8_t id; + if (!dmx->getCADemuxID(id)) + return id; + } + return -1; +} + RESULT eDVBChannel::requestTsidOnid(ePyObject callback) { if (PyCallable_Check(callback)) @@ -1594,17 +1705,24 @@ RESULT eDVBChannel::getDemux(ePtr &demux, int cap) if (m_mgr->allocateDemux(m_frontend ? (eDVBRegisteredFrontend*)*m_frontend : (eDVBRegisteredFrontend*)0, our_demux, cap)) return -1; - } - demux = *our_demux; + demux = *our_demux; + /* don't hold a reference to the decoding demux, we don't need it. */ /* FIXME: by dropping the 'allocated demux' in favour of the 'iDVBDemux', the refcount is lost. thus, decoding demuxes are never allocated. this poses a big problem for PiP. */ - if (cap & capDecode) - our_demux = 0; + + if (cap & capHoldDecodeReference) // this is set in eDVBResourceManager::allocateDemux for Dm500HD/DM800 and DM8000 + ; + else if (cap & capDecode) + our_demux = 0; + } + else + demux = *our_demux; + return 0; } @@ -1640,16 +1758,19 @@ RESULT eDVBChannel::playFile(const char *file) /* DON'T EVEN THINK ABOUT FIXING THIS. FIX THE ATI SOURCES FIRST, THEN DO A REAL FIX HERE! */ + 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); + m_pvr_fd_dst = open("/dev/pvr", O_WRONLY); #else - m_pvr_fd_dst = open("/dev/misc/pvr", O_WRONLY); + m_pvr_fd_dst = open("/dev/misc/pvr", O_WRONLY); #endif - if (m_pvr_fd_dst < 0) - { - eDebug("can't open /dev/misc/pvr - you need to buy the new(!) $$$ box! (%m)"); // or wait for the driver to be improved. - return -ENODEV; + if (m_pvr_fd_dst < 0) + { + eDebug("can't open /dev/misc/pvr - you need to buy the new(!) $$$ box! (%m)"); // or wait for the driver to be improved. + return -ENODEV; + } } m_pvr_thread = new eDVBChannelFilePush(); @@ -1657,10 +1778,14 @@ RESULT eDVBChannel::playFile(const char *file) m_pvr_thread->setStreamMode(1); m_pvr_thread->setScatterGather(this); + m_event(this, evtPreStart); + if (m_pvr_thread->start(file, m_pvr_fd_dst)) { delete m_pvr_thread; m_pvr_thread = 0; + ::close(m_pvr_fd_dst); + m_pvr_fd_dst = -1; eDebug("can't open PVR file %s (%m)", file); return -ENOENT; } @@ -1677,10 +1802,11 @@ void eDVBChannel::stopFile() if (m_pvr_thread) { m_pvr_thread->stop(); - ::close(m_pvr_fd_dst); delete m_pvr_thread; m_pvr_thread = 0; } + if (m_pvr_fd_dst >= 0) + ::close(m_pvr_fd_dst); } void eDVBChannel::setCueSheet(eCueSheet *cuesheet) @@ -1781,7 +1907,7 @@ void eCueSheet::clear() void eCueSheet::addSourceSpan(const pts_t &begin, const pts_t &end) { - assert(begin < end); + ASSERT(begin < end); m_lock.WrLock(); m_spans.push_back(std::pair(begin, end)); m_lock.Unlock();