Hi,

in the attached patch I implemented the evaluation of bookmarks set in the
proprietary header of Topfield-Receiver Recordings (TF4000PVR, TF5xxxPVR, 
TF6xxxPVR... don't know if other Receivers also have that option... maybe 
some store this Information in a separate file?). 

I tried to implement this as robust as possible, so if you don't own such a 
receiver you shouldn't become aware of that new feature.

These bookmarks (if found any) are now automatically set in the marker listbox 
on the left and so for instance help to indentify cut positions marked with 
the receiver. If you don't like this to occur automatically you can switch it 
off in the configuration file with the entry "ts_bookmarks=0".

Furthermore I've now also implemented the "delete all bookmarks" context menu 
entry already "suggested" by Michael... ;-)

And additionally it's now also checked if a marker is already set (otherwise 
you would multiply the bookmarks if stored into a project file). However... I 
don't think that anyone will miss the current "undocumented feature" of 
having thousands of markers for the same frame... ;-)

ciao
Ralph

PS: At the moment I couln't check the new feature for the Tofield DVB-C 
PVR-models, so if you own one it would be nice if you could send me a small 
sample recording with some bookmarks.

PPS: Ahh, Michael... we've now a picturenr(index)-method! :-)
diff -Naur svn/src/dvbcut.cpp my-r91/src/dvbcut.cpp
--- svn/src/dvbcut.cpp	2007-10-17 19:36:48.000000000 +0200
+++ my-r91/src/dvbcut.cpp	2007-10-21 12:04:24.000000000 +0200
@@ -49,6 +49,7 @@
 #include "port.h"
 #include "dvbcut.h"
 #include "mpgfile.h"
+#include "tsfile.h"
 #include "avframe.h"
 #include "eventlistitem.h"
 #include "mplayererrorbase.h"
@@ -612,6 +613,14 @@
 
 void dvbcut::addEventListItem(int pic, EventListItem::eventtype type)
 {
+  //check if requested EventListItem is already in list to avoid doubles!
+  for (QListBoxItem *item=eventlist->firstItem();item;item=item->next())
+    if (item->rtti()==EventListItem::RTTI()) {
+      EventListItem *eli=(EventListItem*)item;
+      if (pic==eli->getpicture() && type==eli->geteventtype()) 
+        return;
+    }
+
   QPixmap p;
   if (imgp && imgp->rtti() == IMAGEPROVIDER_STANDARD)
     p = imgp->getimage(pic);
@@ -932,7 +941,8 @@
   popup.insertItem("Delete",2);
   popup.insertItem("Delete others",3);
   popup.insertItem("Delete all",4);
-  popup.insertItem("Display difference from this picture",5);
+  popup.insertItem("Delete all bookmarks",5);
+  popup.insertItem("Display difference from this picture",6);
 
   QListBox *lb=lbi->listBox();
   QListBoxItem *first=lb->firstItem(),*current,*next;
@@ -970,6 +980,16 @@
       break;
 
     case 5:
+      current=first;
+      while(current) {
+        next=current->next();
+        const EventListItem &eli_current=*static_cast<const EventListItem*>(current);
+        if(eli_current.geteventtype()==EventListItem::bookmark) delete current;
+        current=next;
+      }   
+      break;
+
+    case 6:
       if (imgp)
         delete imgp;
       imgp=new differenceimageprovider(*mpg,eli.getpicture(),new dvbcutbusy(this),false,viewscalefactor);
@@ -1512,6 +1532,16 @@
   }
 
   update_quick_picture_lookup_table();
+
+  // use bookmarks from TS-File (if any and bookmark not already in event list)
+  tsfile *ts=dynamic_cast<tsfile*>(mpg);
+  if(ts && settings().ts_bookmarks) {
+    int pic, nb=0;
+    while(ts->bookmarks[nb])
+      if((pic = mpg->getpictureatposition(ts->bookmarks[nb++])) >= 0) 
+        addEventListItem(pic, EventListItem::bookmark); 
+  }
+
     
   fileOpenAction->setEnabled(true);
   fileSaveAction->setEnabled(true);
diff -Naur svn/src/index.h my-r91/src/index.h
--- svn/src/index.h	2007-10-11 20:03:19.000000000 +0200
+++ my-r91/src/index.h	2007-10-18 17:05:19.000000000 +0200
@@ -141,11 +141,19 @@
     int seq=pic;
     while (seq > 0 && !p[seq].getseqheader())
       --seq;
-    pic=pic-seq;
+    pic-=seq;
     while(seq < pictures && p[seq].getsequencenumber()!=pic)
       ++seq;
     return seq;
     }
+  int picturenr(int ind) const  // the reverse function
+    {
+    int pic=p[ind].getsequencenumber();
+    while (ind > 0 && !p[ind].getseqheader())
+      --ind;
+    pic+=ind-skipfirst;
+    return pic;
+    }
   const picture &operator[](unsigned int i) const
     {
     return p[i];
diff -Naur svn/src/mpgfile.h my-r91/src/mpgfile.h
--- svn/src/mpgfile.h	2007-10-14 01:19:43.000000000 +0200
+++ my-r91/src/mpgfile.h	2007-10-18 17:09:24.000000000 +0200
@@ -127,6 +127,42 @@
       }
     return -1;
     }
+  const int getpictureatposition(dvbcut_off_t position) const
+    {  
+    // binary search for the picture at nearest file position (in bytes)
+    int firstpic=0, lastpic=pictures-1;
+    int first=idx.indexnr(firstpic), mid, last=idx.indexnr(lastpic);
+    dvbcut_off_t firstpos=idx[first].getpos();
+    dvbcut_off_t lastpos=idx[last].getpos();
+    dvbcut_off_t midpos; 
+
+    if(position<firstpos || position>lastpos) return -1;
+
+    while( last-first > 1 )
+    {
+      mid = (first + last)/2;
+      midpos = idx[mid].getpos(); 
+        
+      if(position > midpos) {
+        first = mid;
+        firstpos = midpos;
+      } else if(position < midpos) {
+        last = mid;
+        lastpos = midpos;
+      } else { // equality
+        first = mid;
+        firstpos = midpos;
+        last = mid;
+        lastpos = midpos;
+      }  
+    }
+    
+    // index of picture at nearest file position
+    int ind = (position-firstpos)<(lastpos-position) ? first : last;
+
+    // get the corresponding picture number
+    return idx.picturenr(ind);
+    }
   AVCodecContext *getavcc(int str)
     {
     return s[str].avcc;
diff -Naur svn/src/settings.cpp my-r91/src/settings.cpp
--- svn/src/settings.cpp	2007-10-12 16:12:16.000000000 +0200
+++ my-r91/src/settings.cpp	2007-10-21 12:01:06.000000000 +0200
@@ -109,6 +109,7 @@
     chapter_label = readEntry("/chapter", DVBCUT_DEFAULT_CHAPTER_LABEL);
     bookmark_label = readEntry("/bookmark", DVBCUT_DEFAULT_BOOKMARK_LABEL);
   endGroup();	// labels
+  ts_bookmarks = readNumEntry("/ts_bookmarks", 1);
 }
 
 void
@@ -150,6 +151,7 @@
     writeEntry("/chapter", chapter_label);
     writeEntry("/bookmark", bookmark_label);
   endGroup();	// labels
+  writeEntry("/ts_bookmarks", ts_bookmarks);
 }
 
 // private settings variable
diff -Naur svn/src/settings.h my-r91/src/settings.h
--- svn/src/settings.h	2007-10-12 16:12:16.000000000 +0200
+++ my-r91/src/settings.h	2007-10-21 12:00:13.000000000 +0200
@@ -64,6 +64,7 @@
   QString stop_label;
   QString chapter_label;
   QString bookmark_label;
+  int ts_bookmarks;
 
 };
 
diff -Naur svn/src/tsfile.cpp my-r91/src/tsfile.cpp
--- svn/src/tsfile.cpp	2007-10-11 20:03:19.000000000 +0200
+++ my-r91/src/tsfile.cpp	2007-10-20 20:16:05.000000000 +0200
@@ -29,6 +29,15 @@
   for(unsigned int i=0;i<8192;++i)
     streamnumber[i]=-1;
 
+  // check the "header" for receiver specific bookmarks
+  const uint8_t *header = (const uint8_t*) buf.data();
+  const char *model[6]={"???","TF4000","TF5000","TF5010","TF5000c","TF5010c"};
+  int irc;
+  if((irc=isTOPFIELD(header, initial_offset))>0)
+    fprintf(stderr,"Found Topfield %s header with %d bookmarks\n",model[irc/100],irc%100);  
+  //else
+  //  fprintf(stderr,"Unknown, corrupted or no proprietary TS header at all, IRC=%d\n",irc);
+
   // Find video PID and audio PID(s)
   buf.providedata(buf.getsize(), initialoffset);
   if (check_si_tables())
@@ -241,6 +250,101 @@
   return -1;
 }
 
+// test for Topfield TF4000PVR & TF5xxxPVR and read bookmarks from the proprietary header
+// return codes: <type>*100+<number of bookmarks> or 
+//               -1: header far to short for topfield/bookmarks, -2: magic mismatch, -3: version mismatch                                              
+int tsfile::isTOPFIELD(const uint8_t *header, int len) {  
+  unsigned int magic, version, unit=0;
+  unsigned int frequency, symbolrate, modulation;
+  int boff=len, off=0, type=0, hlen=0, verbose=0;
+
+  // initialize bookmark array! 
+  bookmarks[0] = 0;
+  
+  // just in case there's a corrupted TS packet at the beginning
+  if(verbose) fprintf(stderr,"Header length: %d\n",len);
+  if(len<TSPACKETSIZE) return -1;
+
+  // identify the specific header via the magic number 'TFrc'
+  magic = (header[0]<<24)|(header[1]<<16)|(header[2]<<8)|header[3];
+  if(magic==TF5XXXPVR_MAGIC) {           // all newer models of type TF5???PVR and TF6???PVR
+      hlen = TF5XXXPVR_LEN;
+      unit = (1<<9)*TSPACKETSIZE;
+      // There are 2 different versions, one with 4 bytes larger ServiceInfoStructure (UK models?)
+      version = (header[4]<<8)|header[5];
+      if(verbose) fprintf(stderr,"magic: %x version: %x\n",magic,version);
+      if(version==TF5000PVR_VERSION) {  
+        off = 0;  
+        boff = TF5000PVR_POS;
+        type = 2;
+      } else if(version==TF5010PVR_VERSION) {
+        off = 4;
+        boff = TF5010PVR_POS;
+        type = 3;
+      } else 
+        return -3;          
+      // DVB-C boxes have a 4bytes smaller TransponderInfoStructure... grmbl!!!
+      // And there's no identifier or version number to indicate this... arghhhh!! 
+      // ==> check a few transponder parameters (which are stored at different positions if DVB-S or -T!?!) 
+      frequency = (header[52+off]<<24)|(header[53+off]<<16)|(header[54+off]<<8)|header[55+off];
+      symbolrate = (header[56+off]<<8)|header[57+off];
+      modulation = header[62+off];
+      if(verbose) fprintf(stderr,"DVB-C? freq=%d symb=%d mod=%d\n",frequency,symbolrate,modulation);
+      if(frequency>=47000 && frequency<=862000 && symbolrate>=2000 && symbolrate<=30000 && modulation<=4) {
+        boff-=4;
+        type+=2;
+      }  
+  } else { 
+      // the old TF4000PVR don't writes a simple magic/version number at the beginning...
+      // but start/stop time (MJD/hour/time) ==> check for consistency!
+      // start can be equal to stop (if recording is COPY/CUT), but should be year 2000+ (MJD=51543)!
+      version = (header[4]<<24)|(header[5]<<16)|(header[6]<<8)|header[7];
+      unsigned int duration = (header[8]<<8)|header[9]; // in minutes
+      unsigned int servicetype = (header[12]<<8)|header[13]; // 0:TV, 1:Radio
+      unsigned int polarity = header[53]; // 0x80, 0x08, 0x88, 0x00 (hi/lo, hor/ver)
+      frequency = (header[54]<<8)|header[55];
+      symbolrate = (header[56]<<8)|header[57];
+      if(verbose) fprintf(stderr,"TF4000? start=%x stop=%x dur=%d serv=%d freq=%d symb=%d pol=%d\n",
+                                        magic,version,duration,servicetype,frequency,symbolrate,polarity);
+      if(magic<=version && (magic>>16)>51543 && 
+         header[2]<24 && header[3]<60 && header[6]<24 && header[7]<60 &&
+         duration>0 && duration<1440 && servicetype==0 &&    // up to one full day TV recording should be enough!
+         frequency>=10000 && frequency<=13000 &&             // there's only a DVB-S device, AFAIK!
+         symbolrate>=2000 && symbolrate<=30000 && (polarity&0x77)==0) {
+        // the above should be sufficient... together with the required length of the header!
+        hlen = TF4000PVR_LEN;
+        unit = (1<<17);
+        boff = TF4000PVR_POS;
+        type = 1;
+      } else 
+        return -2;
+  }    
+   
+  // OK,... we identified a receiver model!
+  int bnum = 0; 
+  //if(len>=hlen) // discard ALL (slightly) to small headers...? No, only require enough space for the bookmarks...
+  if(len>=boff+4*MAX_BOOKMARKS) { 
+      // Seems to be a Topfield TF4000PVR/TF5xxxPVR TS-header with 576/3760bytes total length
+      // and up to 64 bookmarks (BUT can be shorter/corrupted due to COPY/CUT-procedure on reveiver)
+      unsigned int bookmark;
+      do {
+          bookmark = (header[boff]<<24)|(header[boff+1]<<16)|(header[boff+2]<<8)|header[boff+3];
+          // bookmark is stored in 128 resp. 94kbyte units
+          bookmarks[bnum] = bookmark*unit;
+          if(verbose && bookmark) fprintf(stderr,"BOOKMARK[%d] = %lld\n",bnum,bookmarks[bnum]);
+          bnum++;
+          boff+=4;
+      }  
+      while(bookmark && bnum<MAX_BOOKMARKS);
+      // add a terminating zero marker!   
+      if(bnum==MAX_BOOKMARKS) bookmarks[bnum] = 0;
+      else bnum--;
+  } else // receiver model identified but header to short!
+      fprintf(stderr,"Header probabely corrupted (%dbytes to short), discarding bookmarks!\n",hlen-len);
+
+  return type*100+bnum;
+}
+
 size_t
 tsfile::get_si_table(uint8_t *tbl, size_t max, size_t &index, int pid, int tid) {
   const uint8_t *d = (uint8_t*)buf.data();
diff -Naur svn/src/tsfile.h my-r91/src/tsfile.h
--- svn/src/tsfile.h	2007-10-11 20:03:19.000000000 +0200
+++ my-r91/src/tsfile.h	2007-10-20 20:14:14.000000000 +0200
@@ -26,6 +26,18 @@
 #define TSPACKETSIZE (188)
 #define TSSYNCBYTE (0x47)
 
+// stuff to identify proprietary (topfield) headers and find bookmarks
+// ==> magic (&version) number, position of bookmarks, length of header
+#define TF5XXXPVR_MAGIC (0x54467263)
+#define TF5XXXPVR_LEN (20*TSPACKETSIZE)
+#define TF5000PVR_VERSION (0x5000)
+#define TF5000PVR_POS (1400)
+#define TF5010PVR_VERSION (0x5010)
+#define TF5010PVR_POS (1404)
+#define TF4000PVR_LEN (3*TSPACKETSIZE)
+#define TF4000PVR_POS (216)
+#define MAX_BOOKMARKS (64)
+
 /**
 @author Sven Over
 */
@@ -90,6 +102,8 @@
   bool check_si_tables();
   size_t get_si_table(uint8_t*, size_t,  size_t&, int, int);
 
+  int isTOPFIELD(const uint8_t*, int);  
+
 public:
   tsfile(inbuffer &b, int initial_offset);
 
@@ -103,6 +117,9 @@
     return true;
   }
 
+  // to store file position of bookmarks (in bytes, terminated by a zero-bookmark)
+  dvbcut_off_t bookmarks[MAX_BOOKMARKS+1];
+
 };
 
 #endif
-------------------------------------------------------------------------
This SF.net email is sponsored by: Splunk Inc.
Still grepping through log files to find problems?  Stop.
Now Search log events and configuration files using AJAX and a browser.
Download your FREE copy of Splunk now >> http://get.splunk.com/
_______________________________________________
DVBCUT-user mailing list
DVBCUT-user@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/dvbcut-user

Reply via email to