[SCM] kodi-pvr-hts/master: create a separate class for figuring out which channel should be tuned to when doing predictive tuning. This new approach has the benefit that it operates on iterators instead of raw numbers, meaning the prediction works as expected even when there are gaps in the channel numbers (fixes #115)

tiber-guest at users.alioth.debian.org tiber-guest at users.alioth.debian.org
Wed Mar 2 23:01:47 UTC 2016


The following commit has been merged in the master branch:
commit 73100c5a29e5d48ef5a2bad1c94aca4beded8922
Author: Sam Stenvall <sam.stenvall at nordsoftware.com>
Date:   Sat Oct 17 15:48:28 2015 +0300

    create a separate class for figuring out which channel should be
    tuned to when doing predictive tuning. This new approach has the
    benefit that it operates on iterators instead of raw numbers,
    meaning the prediction works as expected even when there are gaps
    in the channel numbers (fixes #115)

diff --git a/CMakeLists.txt b/CMakeLists.txt
index e6f56bb..c43917c 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -34,7 +34,9 @@ set(HTS_SOURCES src/AsyncState.cpp
 
 set(HTS_SOURCES_TVHEADEND
                 src/tvheadend/Settings.cpp
-                src/tvheadend/Settings.h)
+                src/tvheadend/Settings.h
+                src/tvheadend/ChannelTuningPredictor.h
+                src/tvheadend/ChannelTuningPredictor.cpp)
 
 set(HTS_SOURCES_TVHEADEND_ENTITY
                 src/tvheadend/entity/AutoRecording.h
diff --git a/src/Tvheadend.cpp b/src/Tvheadend.cpp
index 971a441..a7183b6 100644
--- a/src/Tvheadend.cpp
+++ b/src/Tvheadend.cpp
@@ -1585,6 +1585,11 @@ void CTvheadend::ParseChannelAddOrUpdate ( htsmsg_t *msg, bool bAdd )
     tvhdebug("channel %s id:%u, name:%s",
              (bAdd ? "added" : "updated"), channel.GetId(), channel.GetName().c_str());
 
+    if (bAdd)
+      m_channelTuningPredictor.AddChannel(channel);
+    else
+      m_channelTuningPredictor.UpdateChannel(comparison, channel);
+
     if (m_asyncState.GetState() > ASYNC_CHN)
       TriggerChannelUpdate();
   }
@@ -1604,6 +1609,7 @@ void CTvheadend::ParseChannelDelete ( htsmsg_t *msg )
   
   /* Erase */
   m_channels.erase(u32);
+  m_channelTuningPredictor.RemoveChannel(u32);
   TriggerChannelUpdate();
 }
 
@@ -1959,33 +1965,13 @@ void CTvheadend::TuneOnOldest( uint32_t channelId )
 void CTvheadend::PredictiveTune( uint32_t fromChannelId, uint32_t toChannelId )
 {
   CLockObject lock(m_mutex);
-  uint32_t fromNum, toNum;
-
-  fromNum = m_channels[fromChannelId].GetNum();
-  toNum = m_channels[toChannelId].GetNum();
-
-  if (fromNum + 1 == toNum || toNum == 1)
-  {
-    /* tuning up, or to channel 1 */
-    for (const auto &entry : m_channels)
-    {
-      const Channel &channel = entry.second;
 
-      if (toNum + 1 == channel.GetNum())
-        TuneOnOldest(channel.GetId());
-    }
-  }
-  else if (fromNum - 1 == toNum)
-  {
-    /* tuning down */
-    for (const auto &entry : m_channels)
-    {
-      const Channel &channel = entry.second;
+  /* Consult the predictive tuning helper for which channel
+   * should be predictably tuned next */
+  uint32_t predictedChannelId = m_channelTuningPredictor.PredictNextChannelId(fromChannelId, toChannelId);
 
-      if (toNum - 1 == channel.GetNum())
-        TuneOnOldest(channel.GetId());
-    }
-  }
+  if (predictedChannelId != predictivetune::CHANNEL_ID_NONE)
+    TuneOnOldest(predictedChannelId);
 }
 
 bool CTvheadend::DemuxOpen( const PVR_CHANNEL &chn )
diff --git a/src/Tvheadend.h b/src/Tvheadend.h
index f41004e..d157bbb 100644
--- a/src/Tvheadend.h
+++ b/src/Tvheadend.h
@@ -32,6 +32,7 @@
 #include "tvheadend/Settings.h"
 #include "HTSPTypes.h"
 #include "AsyncState.h"
+#include "tvheadend/ChannelTuningPredictor.h"
 #include "tvheadend/entity/Tag.h"
 #include "tvheadend/entity/Channel.h"
 #include "tvheadend/entity/Recording.h"
@@ -428,6 +429,8 @@ private:
   tvheadend::entity::Recordings m_recordings;
   tvheadend::entity::Schedules  m_schedules;
 
+  tvheadend::ChannelTuningPredictor m_channelTuningPredictor;
+
   SHTSPEventList              m_events;
 
   AsyncState                  m_asyncState;
diff --git a/src/tvheadend/ChannelTuningPredictor.cpp b/src/tvheadend/ChannelTuningPredictor.cpp
new file mode 100644
index 0000000..f60774b
--- /dev/null
+++ b/src/tvheadend/ChannelTuningPredictor.cpp
@@ -0,0 +1,92 @@
+/*
+ *      Copyright (C) 2005-2011 Team XBMC
+ *      http://www.xbmc.org
+ *
+ *  This Program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2, or (at your option)
+ *  any later version.
+ *
+ *  This Program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with XBMC; see the file COPYING.  If not, write to
+ *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ *  http://www.gnu.org/copyleft/gpl.html
+ *
+ */
+
+#include "ChannelTuningPredictor.h"
+#include <algorithm>
+
+using namespace tvheadend;
+using namespace tvheadend::entity;
+using namespace tvheadend::predictivetune;
+
+void ChannelTuningPredictor::AddChannel(const Channel &channel)
+{
+  m_channels.insert(MakeChannelPair(channel));
+}
+
+void ChannelTuningPredictor::UpdateChannel(const Channel &oldChannel, const Channel &newChannel)
+{
+  m_channels.erase(MakeChannelPair(oldChannel));
+  m_channels.insert(MakeChannelPair(newChannel));
+}
+
+void ChannelTuningPredictor::RemoveChannel(uint32_t channelId)
+{
+  auto it = GetIterator(channelId);
+
+  if (it != m_channels.end())
+    m_channels.erase(it);
+}
+
+ChannelPair ChannelTuningPredictor::MakeChannelPair(const entity::Channel &channel)
+{
+  return ChannelPair(channel.GetId(), channel.GetNum());
+}
+
+ChannelPairIterator ChannelTuningPredictor::GetIterator(uint32_t channelId) const
+{
+  return std::find_if(
+      m_channels.cbegin(),
+      m_channels.cend(),
+      [channelId](const ChannelPair &channel)
+      {
+        return channel.first == channelId;
+      }
+  );
+}
+
+uint32_t ChannelTuningPredictor::PredictNextChannelId(uint32_t tuningFrom, uint32_t tuningTo) const
+{
+  auto fromIt = GetIterator(tuningFrom);
+  auto toIt = GetIterator(tuningTo);
+
+  /* Determine the respective channel numbers as well as the first channel */
+  uint32_t fromNum = fromIt->second;
+  uint32_t toNum = toIt->second;
+  uint32_t firstNum = m_channels.cbegin()->second;
+
+  /* Create an iterator for the predicted channel. If prediction succeeds,
+   * it will point at the channel we should tune to */
+  std::set<ChannelPair>::iterator predictedIt = m_channels.cend();
+
+  if (std::next(fromIt, 1) == toIt || toIt->second == firstNum) {
+    /* Tuning up or if we're tuning the first channel */
+    predictedIt = ++toIt;
+  }
+  else if (std::prev(fromIt, 1) == toIt) {
+    /* Tuning down */
+    predictedIt = --toIt;
+  }
+
+  if (predictedIt != m_channels.cend())
+    return predictedIt->first;
+  else
+    return CHANNEL_ID_NONE;
+}
diff --git a/src/tvheadend/ChannelTuningPredictor.h b/src/tvheadend/ChannelTuningPredictor.h
new file mode 100644
index 0000000..a64fbb7
--- /dev/null
+++ b/src/tvheadend/ChannelTuningPredictor.h
@@ -0,0 +1,116 @@
+#pragma once
+
+/*
+ *      Copyright (C) 2005-2015 Team Kodi
+ *      http://www.xbmc.org
+ *
+ *  This Program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2, or (at your option)
+ *  any later version.
+ *
+ *  This Program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with XBMC; see the file COPYING.  If not, write to
+ *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+ *  http://www.gnu.org/copyleft/gpl.html
+ *
+ */
+
+#include "entity/Channel.h"
+#include <set>
+#include <utility>
+
+namespace tvheadend
+{
+
+  namespace predictivetune
+  {
+
+    /**
+     * Used to indicate that predictive tuning failed to determine which
+     * channel to be tuned next
+     */
+    const uint32_t CHANNEL_ID_NONE = -1;
+
+    /**
+     * Defines a single channel ID/number pair
+     */
+    typedef std::pair<uint32_t, uint32_t> ChannelPair;
+    typedef std::set<predictivetune::ChannelPair>::const_iterator ChannelPairIterator;
+
+    /**
+     * Sorter for channel pairs
+     */
+    struct SortChannelPair
+    {
+      bool operator()(const ChannelPair &left, const ChannelPair &right) const
+      {
+        return left.second < right.second;
+      }
+    };
+  }
+
+  /**
+   * This class holds a sorted set of channel "pairs" (ID -> number mapping) and
+   * can be used to predict which channel ID should be tuned after a normal zap
+   * is performed.
+   */
+  class ChannelTuningPredictor
+  {
+  public:
+    /**
+     * Adds the specified channel
+     * @param channel the channel
+     */
+    void AddChannel(const entity::Channel &channel);
+
+    /**
+     * Swaps the old channel with the new channel
+     * @param oldChannel the channel that should be updated
+     * @param newChannel the new channel
+     */
+    void UpdateChannel(const entity::Channel &oldChannel, const entity::Channel &newChannel);
+
+    /**
+     * Removes the channel with the specified channel ID
+     * @param channelId the channel ID
+     */
+    void RemoveChannel(uint32_t channelId);
+
+    /**
+     * Attempts to predict the channel ID that should be tuned
+     * @param tuningFrom the channel number we are tuning away from
+     * @param tuningTo the channel number we are tuning to
+     * @return the predicted channel number that should be tuned in advance, or
+     *         CHANNEL_ID_NONE if nothing could be predicted
+     */
+    uint32_t PredictNextChannelId(uint32_t tuningFrom, uint32_t tuningTo) const;
+
+  private:
+    /**
+     * Constructs a channel pair from the specified channel number
+     * @param channel the channel to construct a pair from
+     */
+    static predictivetune::ChannelPair MakeChannelPair(const entity::Channel &channel);
+
+    /**
+     * Returns an iterator positioned at the channel pair that matches the
+     * specified channel ID. If no match is found, an end iterator is returned
+     * @param channelId the channel ID
+     * @return the iterator
+     */
+    predictivetune::ChannelPairIterator GetIterator(uint32_t channelId) const;
+
+    /**
+     * Set of pairs which map channel IDs to channel numbers. A custsom comparator is
+     * used to ensure that all inserted pairs are always sorted by the channel number.
+     * This way we can get the next/previous channel by simply adjusting iterators.
+     */
+    std::set<predictivetune::ChannelPair, predictivetune::SortChannelPair> m_channels;
+  };
+}

-- 
kodi-pvr-hts packaging



More information about the pkg-multimedia-commits mailing list