OK,... that was easier than expected... ;-)

The attached new patch file contains a version with an menu entry  "Import 
markers" to put MPG bookmarks into the event list using a mpg::getbookmarks() 
method which returns a pointer to the read TS bookmarks (in frame numbers!) 
or NULL if the input file was a PS file!

The conversion to frame numbers occurs in getbookmarks() on-the-fly when 
called for the first time if the TS bookmarks have been read originally as 
byte positions. That way it doesn't matters what the receiver or 
inputfile-specific read function really delivers...  

Guess that version is now much more general... :)

ciao
Ralph
diff -Naur svn/src/dvbcutbase.ui r91-bookmarks2/src/dvbcutbase.ui
--- svn/src/dvbcutbase.ui	2007-10-17 16:34:34.000000000 +0200
+++ r91-bookmarks2/src/dvbcutbase.ui	2007-10-21 20:18:26.000000000 +0200
@@ -373,6 +373,7 @@
         <action name="editBookmarkAction"/>
         <separator/>
         <action name="editSuggestAction"/>
+        <action name="editImportAction"/>
     </item>
     <item text="View" name="viewMenu">
         <action name="viewNormalAction"/>
@@ -662,6 +663,20 @@
     </action>
     <action>
         <property name="name">
+            <cstring>editImportAction</cstring>
+        </property>
+        <property name="enabled">
+            <bool>false</bool>
+        </property>
+        <property name="text">
+            <string>Import markers</string>
+        </property>
+        <property name="accel">
+            <string>I</string>
+        </property>
+    </action>
+    <action>
+        <property name="name">
             <cstring>fileNewAction</cstring>
         </property>
         <property name="iconSet">
@@ -899,6 +914,12 @@
         <slot>editSuggest()</slot>
     </connection>
     <connection>
+        <sender>editImportAction</sender>
+        <signal>activated()</signal>
+        <receiver>dvbcutbase</receiver>
+        <slot>editImport()</slot>
+    </connection>
+    <connection>
         <sender>eventlist</sender>
         <signal>doubleClicked(QListBoxItem*)</signal>
         <receiver>dvbcutbase</receiver>
@@ -1023,6 +1044,7 @@
     <slot>editChapter()</slot>
     <slot>editBookmark()</slot>
     <slot>editSuggest()</slot>
+    <slot>editImport()</slot>
     <slot>doubleclickedeventlist(QListBoxItem *)</slot>
     <slot>eventlistcontextmenu(QListBoxItem *, const QPoint &amp;)</slot>
     <slot>clickedgo()</slot>
diff -Naur svn/src/dvbcut.cpp r91-bookmarks2/src/dvbcut.cpp
--- svn/src/dvbcut.cpp	2007-10-17 19:36:48.000000000 +0200
+++ r91-bookmarks2/src/dvbcut.cpp	2007-10-22 00:15:25.000000000 +0200
@@ -612,6 +612,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);
@@ -654,6 +662,13 @@
     addEventListItem(pic, EventListItem::bookmark);
 }
 
+void dvbcut::editImport()
+{
+  int *bookmark = mpg->getbookmarks();
+  while(bookmark && *bookmark)
+    addEventListItem(*bookmark++, EventListItem::bookmark);
+}
+
 void dvbcut::viewDifference()
 {
   viewNormalAction->setOn(false);
@@ -932,7 +947,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 +986,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);
@@ -1218,6 +1244,7 @@
   editStartAction->setEnabled(false);
   editStopAction->setEnabled(false);
   editSuggestAction->setEnabled(false);
+  editImportAction->setEnabled(false);
   editChapterAction->setEnabled(false);
   editBookmarkAction->setEnabled(false);
 
@@ -1512,7 +1539,7 @@
   }
 
   update_quick_picture_lookup_table();
-    
+
   fileOpenAction->setEnabled(true);
   fileSaveAction->setEnabled(true);
   fileSaveAsAction->setEnabled(true);
@@ -1525,6 +1552,7 @@
   editStartAction->setEnabled(true);
   editStopAction->setEnabled(true);
   editSuggestAction->setEnabled(true);
+  editImportAction->setEnabled(true);
   editChapterAction->setEnabled(true);
   editBookmarkAction->setEnabled(true);
   viewNormalAction->setEnabled(true);
diff -Naur svn/src/dvbcut.h r91-bookmarks2/src/dvbcut.h
--- svn/src/dvbcut.h	2007-10-11 20:03:19.000000000 +0200
+++ r91-bookmarks2/src/dvbcut.h	2007-10-21 20:02:29.000000000 +0200
@@ -132,6 +132,7 @@
   virtual void editStop();
   virtual void editStart();
   virtual void editSuggest();
+  virtual void editImport();
   virtual void viewDifference();
   virtual void viewUnscaled();
   virtual void viewNormal();
diff -Naur svn/src/index.h r91-bookmarks2/src/index.h
--- svn/src/index.h	2007-10-11 20:03:19.000000000 +0200
+++ r91-bookmarks2/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 r91-bookmarks2/src/mpgfile.h
--- svn/src/mpgfile.h	2007-10-14 01:19:43.000000000 +0200
+++ r91-bookmarks2/src/mpgfile.h	2007-10-22 00:17:16.000000000 +0200
@@ -65,6 +65,10 @@
     {
     return false;
     }
+  virtual int *getbookmarks()
+    {
+    return NULL;
+    }
 
   int getinitialoffset() const
     {
@@ -127,6 +131,42 @@
       }
     return -1;
     }
+  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/tsfile.cpp r91-bookmarks2/src/tsfile.cpp
--- svn/src/tsfile.cpp	2007-10-11 20:03:19.000000000 +0200
+++ r91-bookmarks2/src/tsfile.cpp	2007-10-22 00:00:41.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,102 @@
   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! 
+  byte_bookmarks[0] = 0;
+  bytes = true;
+  
+  // 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
+          byte_bookmarks[bnum] = bookmark*unit;
+          if(verbose && bookmark) fprintf(stderr,"BOOKMARK[%d] = %lld\n",bnum,byte_bookmarks[bnum]);
+          bnum++;
+          boff+=4;
+      }  
+      while(bookmark && bnum<MAX_BOOKMARKS);
+      // add a terminating zero marker!   
+      if(bnum==MAX_BOOKMARKS) byte_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 r91-bookmarks2/src/tsfile.h
--- svn/src/tsfile.h	2007-10-11 20:03:19.000000000 +0200
+++ r91-bookmarks2/src/tsfile.h	2007-10-22 00:15:18.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,14 @@
   bool check_si_tables();
   size_t get_si_table(uint8_t*, size_t,  size_t&, int, int);
 
+  int isTOPFIELD(const uint8_t*, int);  
+  // indicates type of read bookmarks (frame numbers or byte positions)
+  bool bytes;
+  // to store the bookmarks in byte positions (terminated by a zero-bookmark)
+  dvbcut_off_t byte_bookmarks[MAX_BOOKMARKS+1];
+  // to store the bookmarks in frame numbers (terminated by a zero-bookmark)
+  int pic_bookmarks[MAX_BOOKMARKS+1];
+
 public:
   tsfile(inbuffer &b, int initial_offset);
 
@@ -102,6 +122,17 @@
   virtual bool istransportstream() {
     return true;
   }
+  virtual int *getbookmarks() {
+    if(bytes) {
+      int pic, nbp=0,nbb=0;
+      while(byte_bookmarks[nbb])
+        if((pic = getpictureatposition(byte_bookmarks[nbb++])) >= 0) 
+          pic_bookmarks[nbp++] = pic;
+      pic_bookmarks[nbp] = 0;
+      bytes = false;
+    } 
+    return pic_bookmarks;
+  }
 
 };
 
-------------------------------------------------------------------------
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