Update httpstream
[vuplus_dvbapp] / lib / dvb / dvb.cpp
old mode 100644 (file)
new mode 100755 (executable)
index 6f9a67f..e32e5f8
@@ -145,19 +145,20 @@ eDVBAdapterLinux::eDVBAdapterLinux(int nr): m_nr(nr)
 #endif
                if (stat(filename, &s))
                        break;
-               ePtr<eDVBFrontend> 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<eDVBFrontend>(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<eDVBFrontend>(fe));
                }
                ++num_fe;
        }
@@ -524,30 +525,46 @@ RESULT eDVBResourceManager::allocateDemux(eDVBRegisteredFrontend *fe, ePtr<eDVBA
        }
        else if (m_boxtype == DM8000 || m_boxtype == DM500HD || m_boxtype == DM800SE || m_boxtype == DM7020HD)
        {
+               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 */
+               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;
                        }
                }
        }
@@ -718,8 +735,7 @@ RESULT eDVBResourceManager::allocateRawChannel(eUsePtr<iDVBChannel> &channel, in
        return 0;
 }
 
-
-RESULT eDVBResourceManager::allocatePVRChannel(eUsePtr<iDVBPVRChannel> &channel)
+RESULT eDVBResourceManager::allocatePVRChannel(const eDVBChannelID &channelid, eUsePtr<iDVBPVRChannel> &channel)
 {
        ePtr<eDVBAllocatedDemux> demux;
 
@@ -730,7 +746,18 @@ RESULT eDVBResourceManager::allocatePVRChannel(eUsePtr<iDVBPVRChannel> &channel)
                m_releaseCachedChannelTimer->stop();
        }
 
-       channel = new eDVBChannel(this, 0);
+       ePtr<eDVBChannel> 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<iDVBFrontendParameters> feparm;
+               ch->setChannel(channelid, feparm);
+       }
+       channel = ch;
        return 0;
 }
 
@@ -797,17 +824,17 @@ int eDVBResourceManager::canAllocateFrontend(ePtr<iDVBFrontendParameters> &fepar
        return bestval;
 }
 
-int tuner_type_channel_default(ePtr<iDVBChannelList> &channellist, const eDVBChannelID &chid)
+int tuner_type_channel_default(ePtr<iDVBChannelList> &channellist, const eDVBChannelID &chid, int &system)
 {
+       system = iDVBFrontend::feSatellite;
        if (channellist)
        {
                ePtr<iDVBFrontendParameters> feparm;
                if (!channellist->getChannelFrontendData(chid, feparm))
                {
-                       int system;
                        if (!feparm->getSystem(system))
                        {
-                               switch(system)
+                               switch (system)
                                {
                                        case iDVBFrontend::feSatellite:
                                                return 50000;
@@ -824,15 +851,16 @@ int tuner_type_channel_default(ePtr<iDVBChannelList> &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_channel> &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,7 +871,7 @@ 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);
                }
        }
 
@@ -923,6 +951,7 @@ int eDVBResourceManager::canAllocateChannel(const eDVBChannelID &channelid, cons
                eDebug("channel not found!");
                goto error;
        }
+       feparm->getSystem(system);
 
        ret = canAllocateFrontend(feparm, simulate);
 
@@ -1186,8 +1215,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");
 
@@ -1311,8 +1354,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 +1385,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 +1412,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 +1587,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 +1639,15 @@ RESULT eDVBChannel::setChannel(const eDVBChannelID &channelid, ePtr<iDVBFrontend
        if (!channelid)
                return 0;
 
+       m_channel_id = channelid;
+       m_mgr->addChannel(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 +1758,12 @@ RESULT eDVBChannel::getDemux(ePtr<iDVBDemux> &demux, int cap)
 {
        ePtr<eDVBAllocatedDemux> &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,7 +1832,7 @@ RESULT eDVBChannel::playSource(ePtr<iTsSource> &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;
@@ -1818,7 +1874,8 @@ RESULT eDVBChannel::playSource(ePtr<iTsSource> &source, const char *streaminfo_f
 
        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(source->isStream());
        m_pvr_thread->setScatterGather(this);
 
        m_event(this, evtPreStart);