commit 877b6008fa700713c697eb9043d63119f9398c07
Author: David Matthews <dm@prolingua.co.uk>
Date:   Fri Oct 14 16:57:26 2011 +0100

    Recording timing from EITpf
    
    This patch adds code to monitor EITpf.  It sets a bookmark when the programme to be recorded changes from
    "following" to "present" and extends the recording period if a programme is still "present" when the
    scheduled recording time has been reached.

diff --git a/mythtv/libs/libmythtv/dtvrecorder.cpp b/mythtv/libs/libmythtv/dtvrecorder.cpp
index e0a5335..1781a55 100644
--- a/mythtv/libs/libmythtv/dtvrecorder.cpp
+++ b/mythtv/libs/libmythtv/dtvrecorder.cpp
@@ -21,6 +21,7 @@
 #include "atscstreamdata.h"
 #include "mpegstreamdata.h"
 #include "dvbstreamdata.h"
+#include "dvbtables.h"
 #include "dtvrecorder.h"
 #include "programinfo.h"
 #include "mythlogging.h"
@@ -72,6 +73,9 @@ DTVRecorder::DTVRecorder(TVRec *rec) :
     _input_pat(NULL),
     _input_pmt(NULL),
     _has_no_av(false),
+    // EIT timing
+    _is_running(false),
+    _is_following(false),
     // statistics
     _packet_count(0),
     _continuity_error_count(0),
@@ -1182,4 +1186,79 @@ bool DTVRecorder::ProcessAVTSPacket(const TSPacket &tspacket)
     return true;
 }
 
+void DTVRecorder::HandleEIT(const DVBEventInformationTable *eit)
+{
+    DVBStreamData *dsd = dynamic_cast<DVBStreamData*>(_stream_data);
+    if (dsd &&
+        TableID::PF_EIT == eit->TableID() &&
+        eit->ServiceID() == dsd->DesiredProgram() &&
+        eit->OriginalNetworkID() == dsd->DesiredNetworkID() &&
+        eit->TSID() == dsd->DesiredTransportID())
+    {
+        for (uint i = 0; i < eit->EventCount(); i++)
+        {
+            QString programId, recordingProgId, recordingTitle;
+            desc_list_t list = MPEGDescriptor::Parse(
+                eit->Descriptors(i), eit->DescriptorsLength(i)); 
+            desc_list_t contentIds =
+                MPEGDescriptor::FindAll(list, DescriptorID::dvb_content_identifier);
+            for (uint j = 0; j < contentIds.size(); j++)
+            {
+                DVBContentIdentifierDescriptor desc(contentIds[j]);
+                if (desc.ContentEncoding() == 0 &&
+                    (desc.ContentType() == 0x01 || desc.ContentType() == 0x31))
+                {
+                    programId = desc.ContentId();
+                }
+            }
+
+            if (curRecording)
+            {
+                recordingProgId = curRecording->GetProgramID();
+                recordingTitle = curRecording->GetTitle();
+            }
+            // The programid in curRecording will have the default authority at the start
+            // so we have a match if they end the same.
+            bool isMatch = false;
+            if (!programId.isEmpty() && !recordingProgId.isEmpty())
+                isMatch = recordingProgId.endsWith(programId.toLower());
+            else
+            {
+                // Fall back to matching on the title.
+                desc_list_t shortEvents =
+                    MPEGDescriptor::FindAll(list, DescriptorID::short_event);
+                for (uint j = 0; j < shortEvents.size(); j++)
+                {
+                    ShortEventDescriptor sed(shortEvents[j]);
+                    // The title may include a subtitle that has been removed
+                    // by a fixup.
+                    if (sed.EventName().startsWith(recordingTitle))
+                    {
+                        isMatch = true;
+                        break;
+                    }
+                }
+            }
+
+            if (eit->Section() == 0)
+            {
+                LOG(VB_GENERAL, LOG_INFO, LOC + QString("Current is now %1").arg(programId));
+                _is_running = isMatch;
+            }
+            else if (eit->Section() == 1)
+            {
+                LOG(VB_GENERAL, LOG_INFO, LOC + QString("Following is now %1").arg(programId));
+                _is_following = isMatch;
+            }
+            if (curRecording)
+            {
+                LOG(VB_GENERAL, LOG_INFO,
+                    LOC + QString("Recording for %1 (%2) running=%3, following=%4")
+                    .arg(curRecording->GetTitle()).arg(recordingProgId)
+                    .arg(_is_running).arg(_is_following));
+            }
+        }
+    }
+}
+
 /* vim: set expandtab tabstop=4 shiftwidth=4: */
diff --git a/mythtv/libs/libmythtv/dtvrecorder.h b/mythtv/libs/libmythtv/dtvrecorder.h
index 25b8c7e..f103b17 100644
--- a/mythtv/libs/libmythtv/dtvrecorder.h
+++ b/mythtv/libs/libmythtv/dtvrecorder.h
@@ -29,7 +29,8 @@ class DTVRecorder :
     public DVBMainStreamListener,
     public ATSCMainStreamListener,
     public TSPacketListener,
-    public TSPacketListenerAV
+    public TSPacketListenerAV,
+    public DVBEITStreamListener
 {
   public:
     DTVRecorder(TVRec *rec);
@@ -86,6 +87,10 @@ class DTVRecorder :
     // Common audio/visual processing
     bool ProcessAVTSPacket(const TSPacket &tspacket);
 
+    // EIT timing information
+    bool IsRunning(void) { return _is_running; }
+    bool IsFollowing(void) { return _is_following; }
+
   protected:
     void FinishRecording(void);
     void ResetForNewFile(void);
@@ -116,6 +121,9 @@ class DTVRecorder :
     virtual void SetCAMPMT(const ProgramMapTable*) {}
     virtual void UpdateCAMTimeOffset(void) {}
 
+    void HandleEIT(const DVBEventInformationTable*);
+    void HandleEIT(const PremiereContentInformationTable*) {}
+
     // file handle for stream
     int _stream_fd;
 
@@ -164,6 +172,9 @@ class DTVRecorder :
     unsigned char _continuity_counter[0x1fff + 1];
     vector<TSPacket> _scratch;
 
+    // EIT timing
+    bool _is_running, _is_following;
+
     // Statistics
     mutable unsigned long long _packet_count;
     mutable unsigned long long _continuity_error_count;
diff --git a/mythtv/libs/libmythtv/dvbrecorder.cpp b/mythtv/libs/libmythtv/dvbrecorder.cpp
index e842e32..d4257f9 100644
--- a/mythtv/libs/libmythtv/dvbrecorder.cpp
+++ b/mythtv/libs/libmythtv/dvbrecorder.cpp
@@ -24,6 +24,7 @@
 // MythTV includes
 #include "dvbstreamhandler.h"
 #include "mpegstreamdata.h"
+#include "dvbstreamdata.h"
 #include "dvbrecorder.h"
 #include "dvbchannel.h"
 #include "tv_rec.h"
@@ -96,6 +97,10 @@ void DVBRecorder::run(void)
     if (_channel && (_channel->GetSIStandard() == "dvb"))
         _stream_data->AddListeningPID(DVB_TDT_PID);
 
+    DVBStreamData *dsd = dynamic_cast<DVBStreamData*>(_stream_data);
+    if (dsd)
+        dsd->AddDVBEITListener(this);
+
     // Make sure the first things in the file are a PAT & PMT
     bool tmp = _wait_for_keyframe_option;
     _wait_for_keyframe_option = false;
@@ -107,6 +112,16 @@ void DVBRecorder::run(void)
     _stream_data->AddWritingListener(this);
     _stream_handler->AddListener(_stream_data, false, true);
 
+    QString recordingProgId = QString("?"), recordingTitle = QString("?");
+    if (curRecording)
+    {
+        recordingProgId = curRecording->GetProgramID();
+        recordingTitle = curRecording->GetTitle();
+    }
+    LOG(VB_GENERAL, LOG_INFO, LOC + QString("Recording %1 (%2) service %3 net %4 transport %5")
+        .arg(recordingTitle).arg(recordingProgId).arg(dsd->DesiredProgram())
+        .arg(dsd->DesiredNetworkID()).arg(dsd->DesiredTransportID()));
+
     while (IsRecordingRequested() && !IsErrored())
     {
         if (PauseAndWait())
@@ -139,6 +154,9 @@ void DVBRecorder::run(void)
     _stream_data->RemoveWritingListener(this);
     _stream_data->RemoveAVListener(this);
 
+    if (dsd)
+        dsd->RemoveDVBEITListener(this);
+
     Close();
 
     FinishRecording();
diff --git a/mythtv/libs/libmythtv/tv_rec.cpp b/mythtv/libs/libmythtv/tv_rec.cpp
index 2eedf68..7011091 100644
--- a/mythtv/libs/libmythtv/tv_rec.cpp
+++ b/mythtv/libs/libmythtv/tv_rec.cpp
@@ -109,6 +109,7 @@ TVRec::TVRec(int capturecardnum)
       // Current recording info
       curRecording(NULL), autoRunJobs(JOB_NONE),
       overrecordseconds(0),
+      eitIsRunning(false), eitIsFollowing(false),
       // Pseudo LiveTV recording
       pseudoLiveTVRecording(NULL),
       nextLiveTVDir(""),            nextLiveTVDirLock(),
@@ -1221,6 +1222,21 @@ void TVRec::run(void)
         // Tell frontends about pending recordings
         HandlePendingRecordings();
 
+        bool isRunning = false, isFollowing = false;
+        if (GetDTVRecorder())
+        {
+            isRunning = GetDTVRecorder()->IsRunning();
+            isFollowing = GetDTVRecorder()->IsFollowing();
+        }
+        if (isRunning && eitIsFollowing && ! eitIsRunning)
+        {
+            // Set a bookmark at the transition from Following to Present.
+            if (curRecording)
+                curRecording->SaveBookmark(GetFramesWritten());
+        }
+        eitIsRunning = isRunning;
+        eitIsFollowing = isFollowing;
+
         // If we are recording a program, check if the recording is
         // over or someone has asked us to finish the recording.
         // Add an extra 60 seconds to the recording end time if we
@@ -1228,9 +1244,20 @@ void TVRec::run(void)
         QDateTime recEnd = (!pendingRecordings.empty()) ?
             recordEndTime.addSecs(60) : recordEndTime;
         if ((GetState() == kState_RecordingOnly) &&
-            (QDateTime::currentDateTime() > recEnd ||
+            ((QDateTime::currentDateTime() > recEnd && !isRunning) ||
              HasFlags(kFlagFinishRecording)))
         {
+            QDateTime actualTime = QDateTime::currentDateTime();
+            QString title;
+            if (curRecording)
+                title = curRecording->GetTitle();
+            if (actualTime > recordEndTime.addSecs(10))
+                LOG(VB_GENERAL, LOG_INFO,
+                    QString("Extended end time of recording of %1 from %2 to %3")
+                        .arg(title)
+                        .arg(recordEndTime.toString("hh:mm:ss"))
+                        .arg(actualTime.toString("hh:mm:ss")));
+
             ChangeState(kState_None);
             ClearFlags(kFlagFinishRecording);
         }
diff --git a/mythtv/libs/libmythtv/tv_rec.h b/mythtv/libs/libmythtv/tv_rec.h
index e867271..59b3d65 100644
--- a/mythtv/libs/libmythtv/tv_rec.h
+++ b/mythtv/libs/libmythtv/tv_rec.h
@@ -369,6 +369,7 @@ class MTV_PUBLIC TVRec : public SignalMonitorListener, public QRunnable
     QDateTime    recordEndTime;
     int          autoRunJobs;
     int          overrecordseconds;
+    bool         eitIsRunning, eitIsFollowing;
 
     // Pending recording info
     PendingMap   pendingRecordings;
