[mythtv-users] Playback causes recording stream corruption

Tony Lill ajlill at ajlc.waterloo.on.ca
Fri Mar 31 19:32:28 UTC 2006


Tony Lill <ajlill at ajlc.waterloo.on.ca> writes:

> Brian Wood <beww at beww.org> writes:
>
>> On Mar 29, 2006, at 5:28 PM, Ben Rigby wrote:
>>
>>> It does appear that the backend doesn't seem able to keep up with the
>>> recording, but I'm at a loss as to why. Even recording and playing
>>> back at once I only get to about 20% CPU usage. The hard drive is a
>>> fairly new drive, and whilst I'm not sure how to check, I'd be
>>> suprised if it couldn't keep up with one recording stream being
>>> written, and one playback stream being read. This is digital SDTV on a
>>> fairly powerful system, it shouldn't be pushing any of the boundaries
>>> of performance. Are there buffers involved in writing recordings to
>>> disk and reading for playback? Can I increase them?
>
> There's some config in one of the menus for HD ring buffer size, or
> something like that, I'm not sure if that does what you
> want. Otherwise look in libs/libmythtv/tv_rec.cpp, and look for calls
> to ringBuffer->SetWriteBufferSize(). It's not called for all the
> recorders, some just use the default (near the top pf
> ThreadedFileWriter.cpp).

Oh I just rememberd, if you do run out of space in the buffer,
mythbackend will log it. I assume you're running it with -v ALL or
something and keeping the output somewhere. Search for IOBOUND. If you
don't see it, then the buffer size is ok, and presumambly the hangup
is with the thread reading the data.

And I'm sorry to report that my patch does not appear to make much
difference to my situation. Here it is anyway. I did manage to
create/catch one of these incidents. When I was started watching a
pre-recorded program (that was on an automouned NFS partition, all
disk I/O stopped on my backend for about 5 seconds, and I got the
driver message, and the frontend couldn't open the file, which is new.


Index: libs/libmythtv/programinfo.h
===================================================================
--- libs/libmythtv/programinfo.h	(revision 9404)
+++ libs/libmythtv/programinfo.h	(working copy)
@@ -219,9 +219,8 @@
     void ClearPositionMap(int type) const;
     void SetPositionMap(frm_pos_map_t &, int type,
                         long long min_frm = -1, long long max_frm = -1) const;
-    void SetPositionMapDelta(frm_pos_map_t &, int type) const;
+    void SetPositionMapDelta(frm_pos_map_t &, int type);
 
-
     // GUI stuff
     void showDetails(void) const;
     void EditRecording(void);
@@ -318,8 +317,19 @@
   private:
     bool ignoreBookmark;
     mutable class ScheduledRecording* record;
+    
+    QString inUseForWhat;
 
-    QString inUseForWhat;
+    void EndPositionMapThread(void);
+    pthread_t posmapThread;
+    bool posmapThreadRunning;
+    QStringList posmapList;
+    QMutex posmapLock;
+
+ protected:
+    static void *StartPostionMapThread(void *);
+    void posmapWorker(void);
+
 };
 
 /** \class ProgramList
Index: libs/libmythtv/programinfo.cpp
===================================================================
--- libs/libmythtv/programinfo.cpp	(revision 9404)
+++ libs/libmythtv/programinfo.cpp	(working copy)
@@ -125,6 +125,8 @@
     inUseForWhat = "";
 
     record = NULL;
+    
+    posmapThreadRunning = false;
 }   
 
 /** \fn ProgramInfo::ProgramInfo(const ProgramInfo &other) 
@@ -223,6 +225,8 @@
     lastInUseTime = other.lastInUseTime;
     record = NULL;
 
+    posmapThreadRunning = false;
+
     return *this;
 }
 
@@ -233,6 +237,8 @@
 {
     if (record != NULL)
         delete record;
+    if( posmapThreadRunning == true )
+      EndPositionMapThread();
 }
 
 /** \fn ProgramInfo::MakeUniqueKey(void) const
@@ -1375,12 +1381,15 @@
     if (playbackHost == "")
         playbackHost = m_hostname;
 
+    // Get the original path it was recorded on
     tmpURL = GetRecordFilename(gContext->GetSettingOnHost("RecordFilePrefix",
                                                           hostname));
 
+    // if we are playing back on the recording host, just return it
     if (playbackHost == hostname)
         return tmpURL;
 
+    // else if we are playing back on this host, check if the path is accessable, if so, use it
     if (playbackHost == m_hostname)
     {
         QFile checkFile(tmpURL);
@@ -1396,6 +1405,7 @@
             return tmpURL;
     }
 
+    // else contruct a url to use myth file transfer protocol
     tmpURL = QString("myth://") +
              gContext->GetSettingOnHost("BackendServerIP", hostname) + ":" +
              gContext->GetSettingOnHost("BackendServerPort", hostname) + "/" +
@@ -2426,12 +2436,63 @@
     }
 }
 
+void *ProgramInfo::StartPostionMapThread(void *wotzit)
+{
+  ProgramInfo *pi = (ProgramInfo *)wotzit;
+  VERBOSE(VB_IMPORTANT,QString("Starting position map thread"));
+  pi->posmapWorker();
+  return(NULL);
+}
+
+void ProgramInfo::EndPositionMapThread(void)
+{
+  posmapLock.lock();
+  posmapList.append(QString("done"));
+  posmapLock.unlock();
+  pthread_join(posmapThread, NULL);
+  VERBOSE(VB_IMPORTANT,QString("Ending position map thread"));
+}
+
+void ProgramInfo::posmapWorker(void)
+{
+  MSqlQuery query(MSqlQuery::InitCon());
+  bool done = false;
+
+  while( ! done ) {
+    if( posmapList.empty() ) {
+      sleep(1);
+    } else {
+      posmapLock.lock();
+      QStringList mylist = posmapList;
+      posmapList.clear();
+      posmapLock.unlock();
+      for ( QStringList::Iterator it = mylist.begin(); it != mylist.end(); ++it ) {
+	if( *it == QString("done") ) {
+	  done = true;
+	  break;
+	}
+	query.prepare(*it);
+	if (!query.exec() || !query.isActive())
+	  MythContext::DBError("delta position map insert", 
+			       query);
+      }
+      mylist.clear(); 
+    }
+  }
+}
+
 void ProgramInfo::SetPositionMapDelta(frm_pos_map_t &posMap,
-                                      int type) const
+                                      int type)
 {
     QMap<long long, long long>::Iterator i;
-    MSqlQuery query(MSqlQuery::InitCon());
+    //    MSqlQuery query(MSqlQuery::InitCon());
+    QString insert;
 
+    if( posmapThreadRunning == false ) {
+      pthread_create(&posmapThread, NULL, StartPostionMapThread, this);
+      posmapThreadRunning = true;
+    }
+
     for (i = posMap.begin(); i != posMap.end(); ++i)
     {
         long long frame = i.key();
@@ -2447,28 +2508,42 @@
 
         if (isVideo)
         {
-            query.prepare("INSERT INTO filemarkup"
+	  //            query.prepare("INSERT INTO filemarkup"
+          //                " (filename, mark, type, offset)"
+          //                " VALUES"
+          //                " ( :PATH , :MARK , :TYPE , :OFFSET );");
+          //  query.bindValue(":PATH", pathname);
+	    insert = QString("INSERT INTO filemarkup"
                           " (filename, mark, type, offset)"
                           " VALUES"
-                          " ( :PATH , :MARK , :TYPE , :OFFSET );");
-            query.bindValue(":PATH", pathname);
+			     " ( \"%1\", %2, %3, %4 );")
+	      .arg(pathname).arg(i.key()).arg(type).arg(i.data());
         }
         else
         {
-            query.prepare("INSERT INTO recordedmarkup"
+          //  query.prepare("INSERT INTO recordedmarkup"
+          //                " (chanid, starttime, mark, type, offset)"
+          //                " VALUES"
+          //                " ( :CHANID , :STARTTIME , :MARK , :TYPE , :OFFSET );");
+          //  query.bindValue(":CHANID", chanid);
+          //  query.bindValue(":STARTTIME", recstartts);
+	    insert = QString("INSERT INTO recordedmarkup"
                           " (chanid, starttime, mark, type, offset)"
                           " VALUES"
-                          " ( :CHANID , :STARTTIME , :MARK , :TYPE , :OFFSET );");
-            query.bindValue(":CHANID", chanid);
-            query.bindValue(":STARTTIME", recstartts);
+                          " ( %1 , \"%2\" , %3 , %4 , %5 );")
+	      .arg(chanid).arg(recstartts.toString("yyyyMMddhhmmss")).arg(i.key()).arg(type).arg(i.data());
         }
-        query.bindValue(":MARK", frame_str);
-        query.bindValue(":TYPE", type);
-        query.bindValue(":OFFSET", offset_str);
+        //query.bindValue(":MARK", frame_str);
+        //query.bindValue(":TYPE", type);
+        //query.bindValue(":OFFSET", offset_str);
         
-        if (!query.exec() || !query.isActive())
-            MythContext::DBError("delta position map insert", 
-                                 query);
+        //if (!query.exec() || !query.isActive())
+        //   MythContext::DBError("delta position map insert", 
+        //                         query);
+	posmapLock.lock();
+	posmapList.append(insert);
+	posmapLock.unlock();
+	  
     }
 }
 


More information about the mythtv-users mailing list