Hi,
with the attached patch DVBcut is able to import bookmarks from
the newest Topfield receiver TF7700HDPVR (BTW a HDTV DVB-S2 model).
Topfield changed the format and the recordings seem to be pure transport
streams now (without any proprietary header containing the bookmarks and
splitted at 1.5GB for export to FAT32 USB-devices... although, the internal
HDD seems to be a ext2 one ;)).
Anyhow,... the bookmarks are now stored in additional *.add-files (in seconds
NOT and not byte positions as before), which are read out if present with the
same basename and location as the input TS. If someone ever wants to
implement bookmark support for another receiver type which uses such a file,
one could move the reading of the file to a separate function...
ciao
Ralph
PS: I had to change buffer::open() to store the file name in
the "files"-structure, to have acces to it in tsfile()... if you know a
better solution let me now... ;-)
--- svn/ChangeLog 2007-11-14 20:04:07.000000000 +0100
+++ r101-tf7700hdpvr/ChangeLog 2007-11-23 20:57:13.000000000 +0100
@@ -1,3 +1,14 @@
+2007-11-23 Ralph Glasstetter <[EMAIL PROTECTED]>
+
+ * src/mpgfile.h
+ * src/tsfile.cpp
+ * src/tsfile.h
+ Import bookmarks from new Topfield TF7700HDPVR
+
+ * src/buffer.cpp
+ * src/buffer.h
+ Store filename in files structure
+
2007-11-12 Michael Riepe <[EMAIL PROTECTED]>
* src/lavfmuxer.cpp:
diff -Naur svn/src/buffer.cpp r101-tf7700hdpvr/src/buffer.cpp
--- svn/src/buffer.cpp 2007-10-14 01:19:43.000000000 +0200
+++ r101-tf7700hdpvr/src/buffer.cpp 2007-11-23 13:55:02.000000000 +0100
@@ -176,7 +176,7 @@
*errmsg = filename + ": open: " + strerror(errno);
return false;
}
- if (!open(fd, errmsg, true)) {
+ if (!open(fd, filename, errmsg, true)) {
if (errmsg)
*errmsg = filename + ": " + *errmsg;
return false;
@@ -185,10 +185,11 @@
}
bool
-inbuffer::open(int fd, std::string *errmsg, bool closeme) {
+inbuffer::open(int fd, std::string filename, std::string *errmsg, bool closeme) {
infile f;
f.fd = fd;
+ f.name = filename;
f.closeme = closeme;
if (pipe_mode) {
// no more files please!
@@ -482,6 +483,12 @@
}
return -1;
}
+
+std::string
+inbuffer::getfilename(int filenum) {
+ return files.at(filenum).name;
+}
+
// OUTBUFFER ****************************************************************
diff -Naur svn/src/buffer.h r101-tf7700hdpvr/src/buffer.h
--- svn/src/buffer.h 2007-10-11 20:03:19.000000000 +0200
+++ r101-tf7700hdpvr/src/buffer.h 2007-11-23 13:54:16.000000000 +0100
@@ -149,6 +149,7 @@
dvbcut_off_t end;
bool closeme;
int fd;
+ std::string name;
};
std::vector<infile> files;
bool eof;
@@ -165,7 +166,7 @@
public:
inbuffer(unsigned int _size, unsigned int mmapsize = 0);
~inbuffer();
- bool open(int fd, std::string *errmsg = 0, bool closeme = false);
+ bool open(int fd, std::string filename, std::string *errmsg = 0, bool closeme = false);
bool open(std::string filename, std::string *errmsg = 0);
void reset();
@@ -191,6 +192,7 @@
dvbcut_off_t getfilesize() const { return filesize; }
dvbcut_off_t getfilepos() const { return pos + readpos; }
int getfilenum(dvbcut_off_t offset, dvbcut_off_t &fileoff);
+ std::string getfilename(int filenum);
void setsequential(bool flag) { sequential = flag; }
};
diff -Naur svn/src/mpgfile.h r101-tf7700hdpvr/src/mpgfile.h
--- svn/src/mpgfile.h 2007-10-22 22:25:20.000000000 +0200
+++ r101-tf7700hdpvr/src/mpgfile.h 2007-11-23 19:55:50.000000000 +0100
@@ -168,6 +168,16 @@
// get the corresponding picture number
return idx.picturenr(ind);
}
+ int getpictureattime(pts_t time) const
+ {
+ int first=idx.indexnr(0), second=idx.indexnr(1);
+ pts_t firstpts=idx[first].getpts(), secondpts=idx[second].getpts();
+
+ int timeperframe=secondpts-firstpts;
+ timeperframe = timeperframe>0 && timeperframe<5000 ? timeperframe : 3003;
+
+ return time/timeperframe;
+ }
AVCodecContext *getavcc(int str)
{
return s[str].avcc;
diff -Naur svn/src/tsfile.cpp r101-tf7700hdpvr/src/tsfile.cpp
--- svn/src/tsfile.cpp 2007-11-03 22:06:15.000000000 +0100
+++ r101-tf7700hdpvr/src/tsfile.cpp 2007-11-23 20:20:06.000000000 +0100
@@ -31,12 +31,13 @@
// 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"};
+ const char *model[7]={"???","TF4000","TF5000","TF5010","TF5000c","TF5010c","TF7700"};
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);
+ bmtype = none;
+ if((irc=isTOPFIELD(header, initial_offset, buf.getfilename(0)))>0)
+ fprintf(stderr,"Found Topfield %s recording (%d bytes header, %d bookmarks)\n",model[irc/100],initial_offset,irc%100);
+ else if(initial_offset>0)
+ fprintf(stderr,"Discarded %d bytes of initial data!\n",initial_offset);
// Find video PID and audio PID(s)
buf.providedata(buf.getsize(), initialoffset);
@@ -253,16 +254,19 @@
// 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) {
+int
+tsfile::isTOPFIELD(const uint8_t *header, int len, std::string recfile) {
unsigned int magic, version, unit=0;
unsigned int frequency, symbolrate, modulation;
- int boff=len, off=0, type=0, hlen=0, verbose=0;
+ int boff=len, off=0, type=0, hlen=0, verbose=0, irc;
- // this routine stores bookmarks as byte positions!
- bytes = true;
+ if(verbose) fprintf(stderr,"Header length of %s: %d\n",recfile.c_str(),len);
- // just in case there's a corrupted TS packet at the beginning
- if(verbose) fprintf(stderr,"Header length: %d\n",len);
+ // topfield receiver with additional info file?
+ if((irc=isTF7700HDPVR(recfile))>0) return irc;
+ else if(verbose) fprintf(stderr,"No TF7700HDPVR! ERROR =%d\n",irc);
+
+ // just in case there's a corrupted TS packet at the beginning
if(len<TSPACKETSIZE) return -1;
// identify the specific header via the magic number 'TFrc'
@@ -323,12 +327,12 @@
// 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*TF_MAX_BOOKMARKS) {
+ if(len>=boff+4*TF5XXXPVR_MAX) {
// 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)
dvbcut_off_t bookmark;
while ((bookmark=(header[boff]<<24)|(header[boff+1]<<16)|(header[boff+2]<<8)|header[boff+3])
- && bnum<TF_MAX_BOOKMARKS) {
+ && bnum<TF5XXXPVR_MAX) {
// bookmark is stored in 128 resp. 94kbyte units
bookmark*=unit;
if(verbose) fprintf(stderr,"BOOKMARK[%d] = %lld\n",bnum,bookmark);
@@ -340,9 +344,96 @@
} else // receiver model identified but header to short!
fprintf(stderr,"Header probabely corrupted (%dbytes to short), discarding bookmarks!\n",hlen-len);
+ // this routine stores bookmarks as byte positions!
+ bmtype = byte;
+
return type*100+bnum;
}
+// newest topfield receivers (i.e. TF7700HDPVR) with additional ADD-file instead of a TS-header
+int
+tsfile::isTF7700HDPVR(std::string recfile) {
+ int verbose=0;
+ std::string addfile;
+
+ // contruct the expected file name of the additonal info file
+ if (!recfile.empty()) {
+ int lastdot = recfile.rfind('.');
+ int lastslash = recfile.rfind('/');
+ if (lastdot >= 0 && lastdot >= lastslash)
+ addfile = recfile.substr(0,lastdot) + ".add";
+ else
+ return -12;
+ } else
+ return -11;
+
+ FILE *pFile;
+ uint8_t *buffer;
+ long len, lSize;
+
+ pFile = fopen(addfile.c_str() , "rb");
+ if (pFile==NULL) return -13;
+
+ // obtain file size
+ fseek (pFile , 0 , SEEK_END);
+ lSize = ftell(pFile);
+ rewind(pFile);
+
+ // allocate memory to contain the whole file
+ buffer = (uint8_t*) malloc(sizeof(uint8_t)*lSize);
+ if (buffer == NULL) {
+ fclose(pFile);
+ return -14;
+ }
+
+ // copy the file into the buffer
+ len = fread(buffer, 1, lSize, pFile);
+ if (len != lSize) {
+ fclose(pFile);
+ free(buffer);
+ return -15;
+ }
+
+ /* the whole file (normally 2636 bytes) is now loaded in the memory buffer. */
+
+ int bnum = 0, boff = TF7700HDPVR_POS+4*TF7700HDPVR_MAX, unit=90000;
+ // there has to be space for up to 48 bookmarks magic number!
+ if(len>=boff+4) {
+ // is it a topfield file?
+ unsigned int magic = (buffer[boff]<<24)|(buffer[boff+1]<<16)|(buffer[boff+2]<<8)|buffer[boff+3];
+ if(magic!=TF5XXXPVR_MAGIC) {
+ fclose(pFile);
+ free(buffer);
+ return -16;
+ }
+ else if(verbose) fprintf(stderr,"Found Topfield ADD-file: %s\n",addfile.c_str());
+
+ boff = TF7700HDPVR_POS;
+ pts_t bookmark;
+ // changed byte order compared to old receivers!?!
+ while ((bookmark=(buffer[boff+3]<<24)|(buffer[boff+2]<<16)|(buffer[boff+1]<<8)|buffer[boff])
+ && bnum<TF7700HDPVR_MAX) {
+ if(verbose) fprintf(stderr,"BOOKMARK[%d] = %lld\n",bnum,bookmark);
+ // bookmark is stored in seconds now, but we'll use full pts!
+ bookmark*=unit;
+ // fill bookmark vector with times
+ time_bookmarks.push_back(bookmark);
+ bnum++;
+ boff+=4;
+ }
+ } else // receiver model identified but file to short!
+ fprintf(stderr,"ADD-File probabely corrupted (%ldbytes to short), discarding bookmarks!\n",TF7700HDPVR_LEN-len);
+
+ // terminate
+ fclose(pFile);
+ free(buffer);
+
+ // this routine stores bookmarks as times!
+ bmtype = time;
+
+ return 600+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 r101-tf7700hdpvr/src/tsfile.h
--- svn/src/tsfile.h 2007-10-22 22:25:20.000000000 +0200
+++ r101-tf7700hdpvr/src/tsfile.h 2007-11-23 19:15:59.000000000 +0100
@@ -27,16 +27,19 @@
#define TSSYNCBYTE (0x47)
// stuff to identify proprietary (topfield) headers and find bookmarks
-// ==> magic (&version) number, position of bookmarks, length of header
+// ==> magic ('TFrc') &version number, position of bookmarks, length of header, max number of bookmarks
#define TF5XXXPVR_MAGIC (0x54467263)
#define TF5XXXPVR_LEN (20*TSPACKETSIZE)
+#define TF5XXXPVR_MAX (64)
#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 TF_MAX_BOOKMARKS (64)
+#define TF7700HDPVR_LEN (2636)
+#define TF7700HDPVR_MAX (48)
+#define TF7700HDPVR_POS (1040)
/**
@author Sven Over
@@ -102,10 +105,13 @@
bool check_si_tables();
size_t get_si_table(uint8_t*, size_t, size_t&, int, int);
- int isTOPFIELD(const uint8_t*, int);
- bool bytes; // indicates type of read bookmarks
- std::vector<dvbcut_off_t> byte_bookmarks; // to store the bookmarks in byte positions
- std::vector<int> pic_bookmarks; // to store the bookmarks in frame numbers
+ int isTOPFIELD(const uint8_t*, int, std::string);
+ int isTF7700HDPVR(std::string);
+ enum bookmarktype { none, byte, time, pic };
+ bookmarktype bmtype; // indicates type of read bookmarks
+ std::vector<int> pic_bookmarks; // to store the bookmarks as frame numbers (returned by getbookmarks)
+ std::vector<dvbcut_off_t> byte_bookmarks; // to store the bookmarks as byte positions
+ std::vector<pts_t> time_bookmarks; // to store the bookmarks as time stamps
public:
tsfile(inbuffer &b, int initial_offset);
@@ -120,13 +126,20 @@
return true;
}
virtual std::vector<int> getbookmarks() {
- if(bytes) {
+ if(bmtype==byte) {
// convert byte positions to frame numbers if not already done/stored
- int pic;
+ int picnr;
for (std::vector<dvbcut_off_t>::iterator b = byte_bookmarks.begin(); b != byte_bookmarks.end(); ++b)
- if((pic = getpictureatposition(*b)) >= 0)
- pic_bookmarks.push_back(pic);
- bytes = false;
+ if((picnr = getpictureatposition(*b)) >= 0)
+ pic_bookmarks.push_back(picnr);
+ bmtype = pic;
+ } else if(bmtype==time) {
+ // convert pts positions to frame numbers if not already done/stored
+ int picnr;
+ for (std::vector<dvbcut_off_t>::iterator b = time_bookmarks.begin(); b != time_bookmarks.end(); ++b)
+ if((picnr = getpictureattime(*b)) >= 0)
+ pic_bookmarks.push_back(picnr);
+ bmtype = pic;
}
return pic_bookmarks;
}
-------------------------------------------------------------------------
This SF.net email is sponsored by: Microsoft
Defy all challenges. Microsoft(R) Visual Studio 2005.
http://clk.atdmt.com/MRT/go/vse0120000070mrt/direct/01/
_______________________________________________
DVBCUT-user mailing list
DVBCUT-user@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/dvbcut-user