Index: programs/mythbackend/scheduler.h
===================================================================
--- programs/mythbackend/scheduler.h	(revision 14616)
+++ programs/mythbackend/scheduler.h	(working copy)
@@ -2,6 +2,7 @@
 #define SCHEDULER_H_
 
 // C++ headers
+#include <map>
 #include <deque>
 #include <vector>
 using namespace std;
@@ -35,7 +36,10 @@
 typedef RecList::iterator RecIter;
 
 typedef vector<int> InputGroupList;
+typedef QMap<int, RecList> CardListMap;
 
+typedef multimap<uint64_t, ProgramInfo*> ConflictMap;
+
 class Scheduler : public QObject
 {
   public:
@@ -77,6 +81,10 @@
     void EnableScheduling(void) { schedulingEnabled = true; }
     void GetNextLiveTVDir(int cardid);
 
+    // constants
+    static const int kConflictMapInterval;
+    static const int kConflictMapHalfInterval;
+
   protected:
     void RunScheduler(void);
     static void *SchedulerThread(void *param);
@@ -100,13 +108,21 @@
     void BuildListMaps(void);
     void ClearListMaps(void);
 
+    bool IsConflicting(const ProgramInfo *p, const ProgramInfo *q,
+                       bool openEnd) const;
+
     bool IsSameProgram(const ProgramInfo *a, const ProgramInfo *b) const;
 
     bool FindNextConflict(const RecList &cardlist,
                           const ProgramInfo *p, RecConstIter &iter,
                           bool openEnd = false) const;
-    const ProgramInfo *FindConflict(const QMap<int, RecList> &reclists,
-                                    const ProgramInfo *p, bool openEnd = false) const;
+
+    ProgramInfo *FindAnyConflict(
+        ConflictMap &map, const ProgramInfo *p, bool openend) const;
+
+    RecList FindAllConflicts(
+        ConflictMap &map, const ProgramInfo *p, bool openend) const;
+
     void MarkOtherShowings(ProgramInfo *p);
     void MarkShowingsList(RecList &showinglist, ProgramInfo *p);
     void BackupRecStatus(void);
@@ -140,7 +156,7 @@
     RecList reclist;
     RecList worklist;
     RecList retrylist;
-    QMap<int, RecList> cardlistmap;
+    ConflictMap conflictmap;
     QMap<int, RecList> recordidlistmap;
     QMap<QString, RecList> titlelistmap;
     QMap<int, InputGroupList> inputgroupmap;
Index: programs/mythbackend/scheduler.cpp
===================================================================
--- programs/mythbackend/scheduler.cpp	(revision 14616)
+++ programs/mythbackend/scheduler.cpp	(working copy)
@@ -38,6 +38,9 @@
 #define LOC QString("Scheduler: ")
 #define LOC_ERR QString("Scheduler, Error: ")
 
+const int Scheduler::kConflictMapInterval     = 1920;
+const int Scheduler::kConflictMapHalfInterval = 960;
+
 Scheduler::Scheduler(bool runthread, QMap<int, EncoderLink *> *tvList,
                      QString tmptable, Scheduler *master_sched) :
     livetvTime(QDateTime())
@@ -750,6 +753,32 @@
     erase_nulls(worklist);
 }
 
+static uint insert(ConflictMap &cmap, const InputGroupList &input_groups,
+                   ProgramInfo *p)
+{
+    uint insert_cnt = 0;
+    uint64_t btimeX = min(p->recstartts.toTime_t(),
+                          p->startts.toTime_t());
+    uint64_t etimeX = max(p->recendts.toTime_t(),
+                          p->endts.toTime_t());
+
+    InputGroupList::const_iterator it = input_groups.begin();
+    for (; it != input_groups.end(); ++it)
+    {
+        uint64_t btime = (((uint64_t)(*it)) << 32) + btimeX;
+        uint64_t etime = (((uint64_t)(*it)) << 32) + etimeX;
+        for (; btime < etime; btime += Scheduler::kConflictMapInterval)
+        {
+            cmap.insert(pair<uint64_t, ProgramInfo*>(btime, p));
+            insert_cnt++;
+        }
+        cmap.insert(pair<uint64_t, ProgramInfo*>(etime, p));
+        insert_cnt++;
+    }
+
+    return insert_cnt;
+}
+
 void Scheduler::BuildListMaps(void)
 {
     RecIter i = worklist.begin();
@@ -760,7 +789,7 @@
             p->recstatus == rsWillRecord ||
             p->recstatus == rsUnknown)
         {
-            cardlistmap[p->cardid].push_back(p);
+            insert(conflictmap, inputgroupmap[p->inputid], p);
             titlelistmap[p->title].push_back(p);
             recordidlistmap[p->recordid].push_back(p);
         }
@@ -769,14 +798,54 @@
 
 void Scheduler::ClearListMaps(void)
 {
-    cardlistmap.clear();
+    conflictmap.clear();
     titlelistmap.clear();
     recordidlistmap.clear();
-    VERBOSE(VB_IMPORTANT, "cache_is_same_program: "
-            <<cache_is_same_program.size());
     cache_is_same_program.clear();
 }
 
+bool Scheduler::IsConflicting(
+    const ProgramInfo *p, const ProgramInfo *q, bool openEnd) const
+{
+    if (!Recording(q))
+        return false;
+
+    if (p == q)
+        return false;
+
+    if (p->cardid != 0 && (p->cardid != q->cardid) &&
+        !GetSharedInputGroup(p->inputid, q->inputid))
+    {
+        return false;
+    }
+
+    if (openEnd && p->chanid != q->chanid)
+    {
+        if (p->recendts < q->recstartts || p->recstartts > q->recendts)
+        {
+            return false;
+        }
+    }
+    else
+    {
+        if (p->recendts <= q->recstartts || p->recstartts >= q->recendts)
+        {
+            return false;
+        }
+    }
+
+    // if two inputs are in the same input group we have a conflict
+    // unless the programs are on the same multiplex.
+    if (p->cardid && (p->cardid != q->cardid) &&
+        GetSharedInputGroup(p->inputid, q->inputid) &&
+        p->GetMplexID() && (p->GetMplexID() == q->GetMplexID()))
+    {
+        return false;
+    }
+
+    return true;
+}
+
 bool Scheduler::IsSameProgram(
     const ProgramInfo *a, const ProgramInfo *b) const
 {
@@ -799,102 +868,91 @@
     RecConstIter      &j,
     bool               openEnd) const
 {
-    bool is_conflict_dbg = false;
-
     for ( ; j != cardlist.end(); j++)
     {
-        const ProgramInfo *q = *j;
+        if (IsConflicting(p, *j, openEnd))
+            return true;
+    }
 
-        if (p == q)
-            continue;
+    return false;
+}
 
-        if (!Recording(q))
-            continue;
+ProgramInfo *Scheduler::FindAnyConflict(
+    ConflictMap &cmap, const ProgramInfo *p, bool openend) const
+{
+    QMap<ProgramInfo*,ProgramInfo*> dups;
+    uint64_t btimeX = p->recstartts.toTime_t() - kConflictMapHalfInterval - 30;
+    uint64_t etimeX = p->recendts.toTime_t()   + kConflictMapHalfInterval + 30;
 
-        if (is_conflict_dbg)
-            cout << QString("\n  comparing with '%1' ").arg(q->title);
+    const InputGroupList &ingrp = inputgroupmap[p->inputid];
+    InputGroupList::const_iterator grpit = ingrp.begin();
+    const ProgramInfo *last = NULL;
+    for (; grpit != ingrp.end(); ++grpit)
+    {
+        uint64_t btime = btimeX | (((uint64_t)*grpit) << 32);
+        ConflictMap::iterator beg = cmap.lower_bound(btime);
+        uint64_t etime = etimeX | (((uint64_t)*grpit) << 32);
+        ConflictMap::iterator end = cmap.upper_bound(etime);
 
-        if (p->cardid != 0 && (p->cardid != q->cardid) &&
-            !GetSharedInputGroup(p->inputid, q->inputid))
+        ConflictMap::iterator it = beg;
+        for (; it != end; ++it)
         {
-            if (is_conflict_dbg)
-                cout << "  cardid== ";
-            continue;
-        }
-
-        if (openEnd && p->chanid != q->chanid)
-        {
-            if (p->recendts < q->recstartts || p->recstartts > q->recendts)
-            {
-                if (is_conflict_dbg)
-                    cout << "  no-overlap ";
+            if ((it->second == last) || dups[it->second])
                 continue;
-            }
+            last = dups[it->second] = it->second;
+            if (IsConflicting(p, it->second, openend))
+                return it->second;
         }
-        else
-        {
-            if (p->recendts <= q->recstartts || p->recstartts >= q->recendts)
-            {
-                if (is_conflict_dbg)
-                    cout << "  no-overlap ";
-                continue;
-            }
-        }
-
-        if (is_conflict_dbg)
-            cout << "\n" <<
-                QString("  cardid's: %1, %2 ").arg(p->cardid).arg(q->cardid) +
-                QString("Shared input group: %1 ")
-                .arg(GetSharedInputGroup(p->inputid, q->inputid)) +
-                QString("mplexid's: %1, %2")
-                .arg(p->GetMplexID()).arg(q->GetMplexID());
-
-        // if two inputs are in the same input group we have a conflict
-        // unless the programs are on the same multiplex.
-        if (p->cardid && (p->cardid != q->cardid) &&
-            GetSharedInputGroup(p->inputid, q->inputid) &&
-            p->GetMplexID() && (p->GetMplexID() == q->GetMplexID()))
-        {
-            continue;
-        }
-
-        if (is_conflict_dbg)
-            cout << "\n  Found conflict" << endl;
-
-        return true;
     }
 
-    if (is_conflict_dbg)
-        cout << "\n  No conflict" << endl;
-
-    return false;
+    return NULL;
 }
 
-const ProgramInfo *Scheduler::FindConflict(
-    const QMap<int, RecList> &reclists,
-    const ProgramInfo        *p,
-    bool openend) const
+RecList Scheduler::FindAllConflicts(
+    ConflictMap &cmap, const ProgramInfo *p, bool openend) const
 {
-    bool is_conflict_dbg = false;
+    RecList list;
 
-    QMap<int, RecList>::const_iterator it = reclists.begin();
-    for (; it != reclists.end(); ++it)
+    QMap<ProgramInfo*,ProgramInfo*> dups;
+    uint64_t btimeX = p->recstartts.toTime_t() - kConflictMapHalfInterval - 30;
+    uint64_t etimeX = p->recendts.toTime_t()   + kConflictMapHalfInterval + 30;
+
+    const InputGroupList &ingrp = inputgroupmap[p->inputid];
+    InputGroupList::const_iterator grpit = ingrp.begin();
+    const ProgramInfo *last = NULL;
+    for (; grpit != ingrp.end(); ++grpit)
     {
-        if (is_conflict_dbg)
+        uint64_t btime = btimeX | (((uint64_t)*grpit) << 32);
+        ConflictMap::iterator beg = cmap.lower_bound(btime);
+        uint64_t etime = etimeX | (((uint64_t)*grpit) << 32);
+        ConflictMap::iterator end = cmap.upper_bound(etime);
+
+        ConflictMap::iterator it = beg;
+        for (; it != end; ++it)
         {
-            cout << QString("Checking '%1' for conflicts on cardid %2")
-                .arg(p->title).arg(it.key());
-        }
+            if ((it->second == last) || dups[it->second])
+                continue;
+            last = dups[it->second] = it->second;
 
-        const RecList &cardlist = *it;
-        RecConstIter k = cardlist.begin();
-        if (FindNextConflict(cardlist, p, k, openend))
-        {
-            return *k;
+            const ProgramInfo *q = last;
+            if (openend && p->chanid != q->chanid)
+            {
+                if (p->recendts < q->recstartts || p->recstartts > q->recendts)
+                    continue;
+            }
+            else
+            {
+                if (p->recendts <= q->recstartts ||
+                    p->recstartts >= q->recendts)
+                    continue;
+            }
+
+            if (IsConflicting(p, it->second, openend))
+                list.push_back(it->second);
         }
     }
 
-    return NULL;
+    return list;
 }
 
 void Scheduler::MarkOtherShowings(ProgramInfo *p)
@@ -1051,7 +1109,7 @@
             }
         }
 
-        const ProgramInfo *conflict = FindConflict(cardlistmap, q);
+        const ProgramInfo *conflict = FindAnyConflict(conflictmap, q, false);
         if (conflict)
         {
             PrintRec(conflict, "        !");
@@ -1100,7 +1158,9 @@
             MarkOtherShowings(p);
         else if (p->recstatus == rsUnknown)
         {
-            const ProgramInfo *conflict = FindConflict(cardlistmap, p, openEnd);
+            const ProgramInfo *conflict =
+                FindAnyConflict(conflictmap, p, openEnd);
+
             if (!conflict)
             {
                 p->recstatus = rsWillRecord;
@@ -1160,18 +1220,10 @@
         if (move_this)
             MarkOtherShowings(p);
 
-        RecList cardlist;
-        QMap<int, RecList>::const_iterator it = cardlistmap.begin();
-        for (; it != cardlistmap.end(); ++it)
+        RecList conflicts = FindAllConflicts(conflictmap, p, false);
+        RecList::iterator k = conflicts.begin();
+        for (; k != conflicts.end(); ++k)
         {
-            RecConstIter it2 = (*it).begin();
-            for (; it2 != (*it).end(); ++it2)
-                cardlist.push_back(*it2);
-        }
-        
-        RecConstIter k = cardlist.begin();
-        for ( ; FindNextConflict(cardlist, p, k); k++)
-        {
             if ((p->recpriority < (*k)->recpriority && !schedMoveHigher &&
                 move_this) || !TryAnotherShowing(*k, !move_this))
             {
