diff options
| author | Andreas Brachold <vdr07@deltab.de> | 2010-11-27 13:36:09 +0000 |
|---|---|---|
| committer | Andreas Brachold <vdr07@deltab.de> | 2010-11-27 13:36:09 +0000 |
| commit | f279ccbfdfcaa4e7301b56ade829cb974aeb5636 (patch) | |
| tree | 2bff18b8a4738140684fa9536fb49a263ab79011 | |
| parent | 1f7ff5d00b83cbeb0afee85042d60aa2e60dbdd0 (diff) | |
| download | xxv-f279ccbfdfcaa4e7301b56ade829cb974aeb5636.tar.gz xxv-f279ccbfdfcaa4e7301b56ade829cb974aeb5636.tar.bz2 | |
* Release vdr2jpeg-0.1.9
Support new vdr filestructure and fileformat(since VDR-1.7.3)
| -rw-r--r-- | contrib/vdr2jpeg/HISTORY | 2 | ||||
| -rw-r--r-- | contrib/vdr2jpeg/Makefile | 26 | ||||
| -rw-r--r-- | contrib/vdr2jpeg/ffm.h | 12 | ||||
| -rw-r--r-- | contrib/vdr2jpeg/gop.cpp | 313 | ||||
| -rw-r--r-- | contrib/vdr2jpeg/gop.h | 61 | ||||
| -rw-r--r-- | contrib/vdr2jpeg/mpegdec.cpp | 383 | ||||
| -rw-r--r-- | contrib/vdr2jpeg/mpegdec.h | 17 | ||||
| -rw-r--r-- | contrib/vdr2jpeg/tools.h | 14 | ||||
| -rw-r--r-- | contrib/vdr2jpeg/vdr2jpeg.cpp | 48 |
9 files changed, 647 insertions, 229 deletions
diff --git a/contrib/vdr2jpeg/HISTORY b/contrib/vdr2jpeg/HISTORY index 0d751a8..b4aa835 100644 --- a/contrib/vdr2jpeg/HISTORY +++ b/contrib/vdr2jpeg/HISTORY @@ -1,3 +1,5 @@ +0.1.9 + Support new vdr filestructure and fileformat(since VDR-1.7.3) 0.1.1 small fixes to build gcc 4.3 update to build with ffmpeg-svn (r15589) diff --git a/contrib/vdr2jpeg/Makefile b/contrib/vdr2jpeg/Makefile index 14cf9ec..a113a1b 100644 --- a/contrib/vdr2jpeg/Makefile +++ b/contrib/vdr2jpeg/Makefile @@ -2,7 +2,7 @@ # # Makefile -- for building vdr2jpeg # -# Copyright (c) 2005-2009 Andreas Brachold +# Copyright (c) 2005-2010 Andreas Brachold # # This code is distributed under the terms and conditions of the # GNU GENERAL PUBLIC LICENSE. See the file COPYING for details. @@ -60,17 +60,18 @@ else endif CXXFLAGS += -fPIC -Wall -Woverloaded-virtual - - ifdef FFMDIR INCLUDES += -I$(FFMDIR) LIBS += -L$(FFMDIR) -L$(FFMDIR)/libavformat -L$(FFMDIR)/libavcodec -L$(FFMDIR)/libavutil -L$(FFMDIR)/libswscale LIBS += -lavformat -lavcodec -lavutil -lswscale else +ifeq ($(shell $(PKG-CONFIG) --exists libavformat && echo 1), 1) INCLUDES += $(shell $(PKG-CONFIG) --cflags libavformat libavcodec libavutil libswscale) -LIBS += $(shell $(PKG-CONFIG) --libs libavformat libavcodec libavutil libswscale) +LIBS += $(shell $(PKG-CONFIG) --libs libavformat libavcodec libavutil libswscale) +endif endif + ifdef STATIC CXXFLAGS += -static endif @@ -81,13 +82,14 @@ endif PRGNAME = vdr2jpeg VERSION = $(shell grep 'static const char \*VERSION *=' vdr2jpeg.cpp | awk '{ print $$6 }' | sed -e 's/[";]//g') ARCHIVE = $(PRGNAME)-$(VERSION) -DEFINES += -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE -D_GNU_SOURCE -D__STDC_CONSTANT_MACROS +DEFINES += -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE -D_GNU_SOURCE -D__STDC_CONSTANT_MACROS FILES = README LIESMICH HISTORY COPYING Makefile \ - gop.cpp gop.h vdr2jpeg.cpp ffm.cpp ffm.h \ - tools.cpp tools.h -OBJS = tools.o gop.o ffm.o -VDR2JPEGOBJS = vdr2jpeg.o - + vdr2jpeg.cpp \ + gop.cpp gop.h \ + mpegdec.cpp mpegdec.h \ + ffm.cpp ffm.h \ + tools.cpp tools.h +OBJS = vdr2jpeg.o tools.o gop.o mpegdec.o ffm.o ################################################################################ # Implicit rules: @@ -102,8 +104,8 @@ VDR2JPEGOBJS = vdr2jpeg.o all: vdr2jpeg .PHONY: all -vdr2jpeg: $(VDR2JPEGOBJS) $(OBJS) - $(CXX) $(CXXFLAGS) $(VDR2JPEGOBJS) $(OBJS) $(FFOBJS) $(LIBS) -o vdr2jpeg +vdr2jpeg: $(OBJS) + $(CXX) $(CXXFLAGS) $(OBJS) $(LIBS) -o vdr2jpeg ifndef DEBUG $(STRIP) $@ endif diff --git a/contrib/vdr2jpeg/ffm.h b/contrib/vdr2jpeg/ffm.h index 4bac40a..21fab77 100644 --- a/contrib/vdr2jpeg/ffm.h +++ b/contrib/vdr2jpeg/ffm.h @@ -14,3 +14,15 @@ extern void ffm_deinitalize(void); extern bool decode(const char* szMPVfile, const char* szTmpMask, int width, int height); + +// Helperclass for proper init/deinit ffmpeg +struct ffminit +{ + ffminit() { + ffm_initalize(); + } + + virtual ~ffminit() { + ffm_deinitalize(); + } +}; diff --git a/contrib/vdr2jpeg/gop.cpp b/contrib/vdr2jpeg/gop.cpp index 2040fc6..56f44e2 100644 --- a/contrib/vdr2jpeg/gop.cpp +++ b/contrib/vdr2jpeg/gop.cpp @@ -1,10 +1,8 @@ /* * Simple program to grab images from VDR Recording * - * Copyright(c) 2005-2008 Andreas Brachold + * Copyright(c) 2005-2010 Andreas Brachold * - * demux ported from vdrsync.pl : Copyright(c) 2005 Peter Sebbel - * * This code is distributed under the terms and conditions of the * GNU GENERAL PUBLIC LICENSE. See the file COPYING for details. * @@ -26,6 +24,7 @@ #include <algorithm> #include "ffm.h" #include "gop.h" +#include "mpegdec.h" bool operator >>(std::istream & i, tFrame & x) { @@ -39,24 +38,23 @@ bool operator >>(std::istream & i, tFrame & x) std::ostream & operator <<(std::ostream & o, const tFrame & x) { - o << "Frame = " << x.nFrame; -#ifdef DEBUG o << " I-Frame = " << x.nIFrame; -#endif // DEBUG - o << " Offset = " << x.u.f.offset; - o << " File = " <<(int) x.u.f.number; -#ifdef DEBUG - o << " Type = " <<(int) x.u.f.type; - o << " Reserved : " << x.u.f.reserved; -#endif // DEBUG +//#ifdef DEBUG +// o << " Offset = " << x.u.pes.offset; +// o << " File = " <<(int) x.u.pes.number; +// o << " Type = " <<(int) x.u.pes.type; +// o << " Reserved : " << x.u.pes.reserved; +//#endif // DEBUG return o; } -bool ReadIndexFile(const std::string & szFolder, std::vector < int >&nFrames, std::vector < std::pair<tFrame,tFrame> > &nGOP) +bool ReadIndexFile(const std::string & szFile, int nIndexVersion, + const std::vector < int >&nFrames, + std::vector < std::pair<tFrame,tFrame> > &nGOP) { - if(szFolder.empty()) { - std::cerr << "Missing VDR-recording folder" << std::endl; + if(szFile.empty()) { + std::cerr << "Missing index file" << std::endl; return false; } @@ -65,72 +63,68 @@ bool ReadIndexFile(const std::string & szFolder, std::vector < int >&nFrames, st return false; } - std::stringstream ss; - ss << szFolder; - if('/' != *szFolder.rbegin()) - ss << '/'; - ss << "index.vdr"; - ss << std::ends; - std::string szFile(ss.str()); try { std::ifstream f(szFile.c_str(), std::ifstream::in | std::ifstream::binary); -
if(f.fail()) { - std::cerr << "Can't open file : " << szFile << std:: - endl; + + if(f.fail()) { + std::cerr << "Can't open file : " << szFile << std::endl; return false; - } - std::vector < int >::const_iterator i = nFrames.begin(); - std::vector < int >::const_iterator e = nFrames.end(); - for(; i != e && f.good(); ++i) { - std::pair<tFrame,tFrame> gop; - tFrame x( (*i) ); - f.seekg(x.nIFrame * 8, std::ifstream::beg); + } + std::vector < int >::const_iterator i = nFrames.begin(); + std::vector < int >::const_iterator e = nFrames.end(); + for(; i != e && f.good(); ++i) { + std::pair<tFrame,tFrame> gop; + tFrame x( *i ); + f.seekg(x.nIFrame * 8, std::ifstream::beg); do { if(!f.good()) { - std::cerr << - "Seek behind end of file : "; + std::cerr << "Seek behind end of file : "; std::cerr << szFile; - std::cerr << " at Frame "; + std::cerr << " at first frame "; std::cerr << x.nIFrame << std::endl; return false; } if(!(f >> x)) { - std::cerr << - "Incomplete struct : "; + std::cerr << "Incomplete struct : "; std::cerr << szFile; - std::cerr << " at Frame "; + std::cerr << " at first frame "; std::cerr << x.nIFrame << std::endl; return false; } - if(x.u.f.type != 1) + if(!x.bIsIFrame(nIndexVersion)) { f.seekg(8 * 2 * -1, std::ifstream::cur); + if(x.nIFrame > 0) --x.nIFrame; + else { + std::cerr << "Missing start struct : "; + std::cerr << szFile; + std::cerr << " at first frame "; + std::cerr << x.nIFrame << std::endl; + return false; + } } } - while(x.u.f.type != 1); // found I-Frame + while(!x.bIsIFrame(nIndexVersion)); // loop until found I-Frame gop.first = x; //Remember I-Frame - do { ++x.nIFrame; if(!f.good()) { - std::cerr << - "Seek behind end of file : "; + std::cerr << "Seek behind end of file : "; std::cerr << szFile; - std::cerr << " at Frame "; + std::cerr << " at second frame "; std::cerr << x.nIFrame << std::endl; return false; } if(!(f >> x)) { #ifdef DEBUG - std::cerr << - "Incomplete struct : "; + std::cerr << "Incomplete struct : "; std::cerr << szFile; std::cerr << " at Frame "; std::cerr << x.nIFrame << std::endl; @@ -138,7 +132,7 @@ bool ReadIndexFile(const std::string & szFolder, std::vector < int >&nFrames, st return true; } } - while(f.good() && x.u.f.type != 1); // Build IBBP..I -> break on next I-Frame + while(f.good() && !x.bIsIFrame(nIndexVersion)); // Build IBBP..I -> break on next I-Frame gop.second = x; nGOP.push_back(gop); //Remember I-Frame } @@ -151,28 +145,21 @@ bool ReadIndexFile(const std::string & szFolder, std::vector < int >&nFrames, st } } -bool ReadIndexFileFull(const std::string & szFolder, +bool ReadIndexFileFull(const std::string & szFile, int nIndexVersion, std::vector < std::pair<tFrame,tFrame> > &nGOP, bool bIntraOnly, unsigned int &nFirst, unsigned int nLimit) { - if(szFolder.empty()) { - std::cerr << "Missing VDR-recording folder" << std::endl; + if(szFile.empty()) { + std::cerr << "Missing index file" << std::endl; return false; } - std::stringstream ss; - ss << szFolder; - if('/' != *szFolder.rbegin()) - ss << '/'; - ss << "index.vdr"; - ss << std::ends; - std::string szFile(ss.str()); - try { std::ifstream f(szFile.c_str(), std::ifstream::in | std::ifstream::binary); -
if(f.fail()) { + + if(f.fail()) { std::cerr << "Can't open file : " << szFile << std:: endl; return false; @@ -192,7 +179,7 @@ bool ReadIndexFileFull(const std::string & szFolder, std::cerr << x.nIFrame << std::endl; return false; } - if(x.u.f.type == 1) { + if(x.bIsIFrame(nIndexVersion)) { break; } ++x.nFrame; @@ -217,7 +204,7 @@ bool ReadIndexFileFull(const std::string & szFolder, } ++x.nFrame; ++x.nIFrame; - if(!bIntraOnly || x.u.f.type == 1) { + if(!bIntraOnly || x.bIsIFrame(nIndexVersion)) { break; } } while(f.good()); @@ -461,7 +448,7 @@ bool ReadGOP(const std::string & szFile, int nBegin, int nLength, char *pMem ) return true; } -bool ReadRecordings(const std::string & szFolder, +bool ReadRecordings(const std::string & szFolder, int nIndexVersion, const std::string & szOutPath, const std::string & szTempPath, const std::vector < std::pair<tFrame,tFrame> > &nGOP, int width, int height, bool exact, bool bJPEG) @@ -478,6 +465,7 @@ bool ReadRecordings(const std::string & szFolder, return false; } + unsigned int nError = 0; std::vector < std::pair<tFrame,tFrame> >::const_iterator i = nGOP.begin(); std::vector < std::pair<tFrame,tFrame> >::const_iterator e = nGOP.end(); @@ -489,7 +477,7 @@ bool ReadRecordings(const std::string & szFolder, #endif //DEBUG //Skip empty frames (most at end) - if(i->first.u.f.offset == i->second.u.f.offset) { + if(i->first.GetOffset(nIndexVersion) == i->second.GetOffset(nIndexVersion)) { continue; } @@ -509,21 +497,18 @@ bool ReadRecordings(const std::string & szFolder, try { char *pMem = NULL; - int nSize = 0; + off_t nSize = 0; // Offset bigger then current 00x.vdr files, goto next - if((i->first.u.f.offset >= i->second.u.f.offset - || i->first.u.f.number != i->second.u.f.number) - && i->second.u.f.offset != 0) { + if((i->first.GetOffset(nIndexVersion) >= i->second.GetOffset(nIndexVersion) + || i->first.GetFileNr(nIndexVersion) != i->second.GetFileNr(nIndexVersion)) + && i->second.GetOffset(nIndexVersion) != 0) { ss.str(""); ss << szFolder; if('/' != *szFolder.rbegin()) ss << '/'; - ss.fill('0'); - ss.width(3); - ss << (int)i->first.u.f.number; // Filenumber 001.vdr ... - ss << ".vdr"; + i->first.buildFilename(ss,nIndexVersion); // Filenumber 001.vdr ... ss << std::ends; std::string szFile(ss.str()); @@ -534,13 +519,13 @@ bool ReadRecordings(const std::string & szFolder, return false; } - if(i->first.u.f.offset >=(ds.st_size)) { + if(i->first.GetOffset(nIndexVersion) >= (ds.st_size)) { std::cerr << "Offset bigger than current file : " << szFile << std::endl; std::cerr << i->first << " / " << i->second << std::endl; return false; } - nSize = ds.st_size - i->first.u.f.offset + i->second.u.f.offset; + nSize = ds.st_size - i->first.GetOffset(nIndexVersion) + i->second.GetOffset(nIndexVersion); if(nSize <= 0 || nSize >=(1 << 24) || NULL ==(pMem = new char[nSize])) { @@ -550,7 +535,7 @@ bool ReadRecordings(const std::string & szFolder, return false; } - if(!ReadGOP(szFile, i->first.u.f.offset, ds.st_size - i->first.u.f.offset, pMem)) { + if(!ReadGOP(szFile, i->first.GetOffset(nIndexVersion), ds.st_size - i->first.GetOffset(nIndexVersion), pMem)) { delete[]pMem; return false; } @@ -559,10 +544,7 @@ bool ReadRecordings(const std::string & szFolder, ss << szFolder; if('/' != *szFolder.rbegin()) ss << '/'; - ss.fill('0'); - ss.width(3); - ss << (int)i->second.u.f.number; // Filenumber 002.vdr ... - ss << ".vdr"; + i->second.buildFilename(ss,nIndexVersion); // Filenumber 002.vdr ... ss << std::ends; szFile = ss.str(); @@ -572,13 +554,13 @@ bool ReadRecordings(const std::string & szFolder, return false; } - if(i->second.u.f.offset >=(ds.st_size)) { + if(i->second.GetOffset(nIndexVersion) >=(ds.st_size)) { std::cerr << "Offset bigger than current file : " << szFile << std::endl; std::cerr << i->first << " / " << i->second << std::endl; return false; } - if(!ReadGOP(szFile, 0, i->second.u.f.offset, pMem + i->first.u.f.offset)) { + if(!ReadGOP(szFile, 0, i->second.GetOffset(nIndexVersion), pMem + i->first.GetOffset(nIndexVersion))) { delete[]pMem; return false; } @@ -589,10 +571,7 @@ bool ReadRecordings(const std::string & szFolder, ss << szFolder; if('/' != *szFolder.rbegin()) ss << '/'; - ss.fill('0'); - ss.width(3); - ss << (int)i->first.u.f.number; // Filenumber 001.vdr ... - ss << ".vdr"; + i->first.buildFilename(ss,nIndexVersion); // Filenumber 001.vdr ... ss << std::ends; std::string szFile(ss.str()); @@ -603,14 +582,16 @@ bool ReadRecordings(const std::string & szFolder, std::cerr << i->first << " / " << i->second << std::endl; return false; } - if(i->first.u.f.offset >=(ds.st_size)) { + if(i->first.GetOffset(nIndexVersion) >=(ds.st_size)) { std::cerr << "Offset bigger than current file : " << szFile << std::endl; std::cerr << i->first << " / " << i->second << std::endl; return false; } // size of GOP - nSize = i->second.u.f.offset ? i->second.u.f.offset - i->first.u.f.offset : ds.st_size - i->first.u.f.offset; + nSize = i->second.GetOffset(nIndexVersion) + ? i->second.GetOffset(nIndexVersion) - i->first.GetOffset(nIndexVersion) + : ds.st_size - i->first.GetOffset(nIndexVersion); if(nSize <= 0 || nSize >=(1 << 24) || NULL ==(pMem = new char[nSize])) @@ -621,7 +602,7 @@ bool ReadRecordings(const std::string & szFolder, return false; } - if(!ReadGOP(szFile, i->first.u.f.offset, nSize, pMem)) { + if(!ReadGOP(szFile, i->first.GetOffset(nIndexVersion), nSize, pMem)) { delete[]pMem; return false; } @@ -629,104 +610,85 @@ bool ReadRecordings(const std::string & szFolder, /* -00 00 01 // Startcode +00 00 01 // PES Startcode e4 // Streamtype 07 fa // Length => 2042 84 c0 // notused 0b // header_length */ - static const unsigned char packetMagic[3] = { 0x00, 0x00, 0x01 }; - if(0 != memcmp(pMem, packetMagic, 3)) - { - std::cerr << "No valid magic found, at current packet, for file : " << szFolder << std::endl; + int nMagicFormat = -1; + static const unsigned char pesMagic[3] = { 0x00, 0x00, 0x01 }; + static const unsigned char tsMagic[3] = { 0x47, 0x40, 0x00 }; + if(0 == memcmp(pMem, pesMagic, sizeof(pesMagic))) { + nMagicFormat = 1; + } else if(0 == memcmp(pMem, tsMagic, sizeof(tsMagic))) { + nMagicFormat = 2; + } else { + std::cerr << "No valid magic found, at current pes packet, for file : " << szFolder << std::endl; std::cerr << i->first << " / " << i->second << std::endl; - std::cerr.fill('0'); - std::cerr.width(2); - std::cerr << "found : 0x" - << std::hex << (unsigned int)(*(pMem + 0) & 0xFF) - << std::hex << (unsigned int)(*(pMem + 1) & 0xFF) - << std::hex << (unsigned int)(*(pMem + 2) & 0xFF) - << " streamcode : 0x"; - std::cerr.fill('0'); - std::cerr.width(2); - std::cerr <<(unsigned int)(*(pMem + 3)) << std::endl; - delete[]pMem; - return false; - } - int nOffset = 0; - int nPackets = 0; - - - std::ofstream fo; - - while(nOffset < nSize) - { - int pLength =(((unsigned char) *(pMem + nOffset + 4)) << 8) + - (((unsigned char) *(pMem + nOffset + 5)) << 0); - int hLength =(((unsigned char) *(pMem + nOffset + 8)) << 0); - unsigned char cStream =(unsigned char) *(pMem + nOffset + 3); - if((cStream & 0xe0) == 0xe0) - { // Check for Stream 0xE0-0xEF - // Store payload - // |Header|......PaketLength| - unsigned char *pBuffer =(unsigned char *) pMem + nOffset + 9 + hLength; - unsigned int nWrite =(pLength + 6) -(9 + hLength); - - if(!fo.is_open()) // Open on first write. - { - fo.open(szTmpMVP.c_str(), std::ofstream::out | std::ofstream::binary); - if(!fo.good()) - break; - } - fo.write((char *) pBuffer, nWrite); - if(!fo.good()) - break; - - ++nPackets; +#ifdef DEBUG +#if 0 + for(unsigned int b = 0; b < nSize; ++b) { + if(0 == b % 16) { + std::cerr << std::endl; + std::cerr.fill('0'); + std::cerr.width(4); + std::cerr << std::hex << b; + std::cerr << " "; + } +#else + std::cerr << "magic and streamcode are : "; + for(unsigned int b = 0; b < 4 && b < nSize; ++b) { +#endif + std::cerr.fill('0'); + std::cerr.width(2); + std::cerr << std::hex << (unsigned int)(*(pMem + b) & 0xFF); + std::cerr << " "; } - nOffset +=(pLength + 6); - - - if(nOffset <= 0) // avoid negativ seek - break; - } - if(nPackets == 0 && nOffset >= nSize) - { - std::cerr << "No valid packet found, for file : " << szFolder << std::endl; - std::cerr << i->first << " / " << i->second << std::endl; + std::cerr << std::endl; +#endif delete[]pMem; return false; } - std::stringstream so; - so << szTmpBase; - so << "%2d"; - so << (bJPEG ? ".jpg" : ".ppm"); - so << std::ends; - std::string szTmpMask(so.str()); - - bool bRet = decode(szTmpMVP.c_str(), szTmpMask.c_str(), width, height); - if(bRet) + bool bRet = false; + if(nMagicFormat == 1) { + demux_reset(); + bRet = 0 == demuxPES ((uint8_t*)pMem,(uint8_t*)pMem + nSize, szTmpMVP.c_str(), 0); + } else { + demux_reset(); + bRet = 0 == demuxTS ((uint8_t*)pMem,(uint8_t*)pMem + nSize, szTmpMVP.c_str(), 0); + } + if(bRet) { - if(!handleTmpfile(szTmpBase, szOutPath,i->first.nFrame, - i->first.nIFrame, exact, bJPEG, bJPEG,width, height)) { - std::cerr << "Can't handle file : " << szFolder << std::endl; - std::cerr << i->first << " / " << i->second << std::endl; - return false; - } - - // look for more picture from same GOP - std::vector < std::pair<tFrame,tFrame> >::const_iterator j = i + 1; - std::vector < std::pair<tFrame,tFrame> >::const_iterator e = nGOP.end(); - for(;j != e; ++j ,++i) - { - if((i->first.nIFrame != j->first.nIFrame ) - ||(!handleTmpfile(szTmpBase, szOutPath,i->first.nFrame, - i->first.nIFrame, exact, bJPEG, bJPEG, width, height))) - break; - } + std::stringstream so; + so << szTmpBase; + so << "%2d"; + so << (bJPEG ? ".jpg" : ".ppm"); + so << std::ends; + std::string szTmpMask(so.str()); + bRet = decode(szTmpMVP.c_str(), szTmpMask.c_str(), width, height); + if(bRet) + { + if(!handleTmpfile(szTmpBase, szOutPath,i->first.nFrame, + i->first.nIFrame, exact, bJPEG, bJPEG,width, height)) { + std::cerr << "Can't handle file : " << szFolder << std::endl; + std::cerr << i->first << " / " << i->second << std::endl; + return false; + } + + // look for more picture from same GOP + std::vector < std::pair<tFrame,tFrame> >::const_iterator j = i + 1; + std::vector < std::pair<tFrame,tFrame> >::const_iterator e = nGOP.end(); + for(;j != e; ++j ,++i) + { + if((i->first.nIFrame != j->first.nIFrame ) + ||(!handleTmpfile(szTmpBase, szOutPath,i->first.nFrame, + i->first.nIFrame, exact, bJPEG, bJPEG, width, height))) + break; + } + } } - unlinkTmpfiles(szTmpBase, bJPEG); delete[]pMem; @@ -734,7 +696,7 @@ e4 // Streamtype { std::cerr << "decode failed, for file : " << szFolder << std::endl; std::cerr << i->first << " / " << i->second << std::endl; - return false; + nError += 1; } } catch(...) @@ -743,7 +705,7 @@ e4 // Streamtype return false; } } - return true; + return (nError == 0); } bool decodegop(const std::string & szFile, @@ -778,11 +740,12 @@ bool decodegop(const std::string & szFile, unlinkTmpfiles(szTmpBase, bJPEG); return bRet; + } catch(...) { std::cerr << "Something fail at read " << szFile << std::endl; - return -1; } + return false; } diff --git a/contrib/vdr2jpeg/gop.h b/contrib/vdr2jpeg/gop.h index 92ba7d9..410ae4a 100644 --- a/contrib/vdr2jpeg/gop.h +++ b/contrib/vdr2jpeg/gop.h @@ -1,9 +1,9 @@ /* * Simple program to grab images from VDR Recording * - * Copyright(c) 2005-2008 Andreas Brachold + * Copyright(c) 2005-2010 Andreas Brachold * - * demux ported from vdrsync.pl : Copyright(c) 2005 Peter Sebbel + * pes demux ported from vdrsync.pl : Copyright(c) 2005 Peter Sebbel * * This code is distributed under the terms and conditions of the * GNU GENERAL PUBLIC LICENSE. See the file COPYING for details. @@ -13,6 +13,7 @@ #include <iostream> #include <fstream> #include <vector> +#include <stdint.h> struct tFrame { @@ -20,13 +21,18 @@ struct tFrame unsigned int nIFrame; union uIndex { - struct tIndex - { + struct tIndexPES { int32_t offset; unsigned char type; unsigned char number; int16_t reserved; - } f; + } pes; + struct tIndexTS { + uint64_t offset:40; // up to 1TB per file (not using off_t here - must definitely be exactly 64 bit!) + int reserved:7; // reserved for future use + int independent:1; // marks frames that can be displayed by themselves (for trick modes) + uint16_t number:16; // up to 64K files per recording + } ts; char rawdata[8]; } u; tFrame() @@ -34,18 +40,51 @@ struct tFrame }; tFrame(int n) { - nFrame = nIFrame = n; - } + nFrame = n; + nIFrame = n - 6; + if(n <= 6) + nIFrame = 0; + }; + bool bIsIFrame(int nVersion) const { + if(nVersion == 0) { + return u.pes.type == 1; + } else { + return u.ts.independent != 0; + } + }; + off_t GetOffset(int nVersion) const { + if(nVersion == 0) { + return u.pes.offset; + } else { + return u.ts.offset; + } + }; + unsigned int GetFileNr(int nVersion) const { + if(nVersion == 0) { + return u.pes.number; + } else { + return u.ts.number; + } + }; + void buildFilename(std::ostream & o, int nVersion) const { + o.fill('0'); + o.width(nVersion == 0 ? 3 : 5); + o << GetFileNr(nVersion); // Filenumber 002.vdr ... + if(nVersion == 0) + o << ".vdr"; + else + o << ".ts"; + }; }; bool operator >> (std::istream & i, tFrame & x); std::ostream & operator <<(std::ostream & o, const tFrame & x); -bool ReadIndexFile(const std::string & szFolder, std::vector < int >&nFrames, - std::vector < std::pair<tFrame,tFrame> > &nGOP); +bool ReadIndexFile(const std::string & szFile, int nIndexVersion, + const std::vector < int >&nFrames, std::vector < std::pair<tFrame,tFrame> > &nGOP); -bool ReadIndexFileFull(const std::string & szFolder, +bool ReadIndexFileFull(const std::string & szFile, int nIndexVersion, std::vector < std::pair<tFrame,tFrame> > &nGOP, bool bIntraOnly, unsigned int &nFirst, unsigned int nLimit); @@ -60,7 +99,7 @@ bool handleTmpfile(const std::string & szTmpBase, const std::string & szOutPath, int nFrame, int nFrameBase, bool exact, bool bJPEG, bool bLink, unsigned int nWidth,unsigned int nHeight); -bool ReadRecordings(const std::string & szFolder, +bool ReadRecordings(const std::string & szFolder, int nIndexVersion, const std::string & szOutPath, const std::string & szTempPath, const std::vector < std::pair<tFrame,tFrame> > &nGOP, int width, int height, bool exact, bool bJPEG = true); diff --git a/contrib/vdr2jpeg/mpegdec.cpp b/contrib/vdr2jpeg/mpegdec.cpp new file mode 100644 index 0000000..bd26ebd --- /dev/null +++ b/contrib/vdr2jpeg/mpegdec.cpp @@ -0,0 +1,383 @@ +/* + * Simple program to grab images from VDR Recording + * + * Copyright(c) 2010 Andreas Brachold + * + * This code is distributed under the terms and conditions of the + * GNU GENERAL PUBLIC LICENSE. See the file COPYING for details. + */ +/* + the demuxer is based on the original demuxer from mpeg2dec.c + Copyright (C) 2000-2003 Michel Lespinasse <walken@zoy.org> + Copyright (C) 1999-2000 Aaron Holtzman <aholtzma@ess.engr.uvic.ca> +*/ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <inttypes.h> +#include "mpegdec.h" + + +#define DEMUX_HEADER 0 +#define DEMUX_DATA 1 +#define DEMUX_SKIP 2 + +#define DEMUX_PAYLOAD_START 1 +#define DEMUX_RESET 2 + +static int state = DEMUX_SKIP; +static int state_bytes = 0; +static int demux_pid = 0; +static int demux_track = 0xE0; + +void demux_reset(void) +{ + state = DEMUX_SKIP; + state_bytes = 0; + demux_pid = 0; + demux_track = 0xE0; +} + +static bool store_mpeg2 (unsigned char * current, unsigned char * end, const char* f) +{ + FILE * d; + d = fopen (f, "ab"); + if (!d) { + fprintf (stderr, "Could not open file \"%s\".\n", f); + demux_reset(); + return false; + } + + fwrite (current, 1, end-current, d); + fclose (d); + return true; +} + + +// from mpeg2dec.cpp +int demuxPES (unsigned char * buf, unsigned char * end, const char* f, int flags) +{ + int iRet = 0; + static int mpeg1_skip_table[16] = + { + 0, 0, 4, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + }; + + /* + * the demuxer keeps some state between calls: + * if "state" = DEMUX_HEADER, then "head_buf" contains the first + * "bytes" bytes from some header. + * if "state" == DEMUX_DATA, then we need to copy "bytes" bytes + * of ES data before the next header. + * if "state" == DEMUX_SKIP, then we need to skip "bytes" bytes + * of data before the next header. + * + * NEEDBYTES makes sure we have the requested number of bytes for a + * header. If we dont, it copies what we have into head_buf and returns, + * so that when we come back with more data we finish decoding this header. + * + * DONEBYTES updates "buf" to point after the header we just parsed. + */ + + + static unsigned char head_buf[264]; + + unsigned char * header; + int bytes; + int len; + +#define NEEDBYTES(x) \ + do { \ + int missing; \ + \ + missing = (x) - bytes; \ + if (missing > 0) { \ + if (header == head_buf) { \ + if (missing <= end - buf) { \ + memcpy (header + bytes, buf, missing); \ + buf += missing; \ + bytes = (x); \ + } else { \ + memcpy (header + bytes, buf, end - buf); \ + state_bytes = bytes + end - buf; \ + return iRet; \ + } \ + } else { \ + memcpy (head_buf, header, bytes); \ + state = DEMUX_HEADER; \ + state_bytes = bytes; \ + return iRet; \ + } \ + } \ + } while (0) + +#define DONEBYTES(x) \ + do { \ + if (header != head_buf) \ + buf = header + (x); \ + } while (0) + + if (flags & DEMUX_RESET) + { + state = DEMUX_SKIP; + state_bytes = 0; + } + if (flags & DEMUX_PAYLOAD_START) + { + state = DEMUX_SKIP; + goto payload_start; + } + switch (state) + { + case DEMUX_HEADER: + if (state_bytes > 0) + { + header = head_buf; + bytes = state_bytes; + goto continue_header; + } + break; + + case DEMUX_DATA: + if (demux_pid || (state_bytes > end - buf)) + { + if(!store_mpeg2 (buf, end, f)) + if(state == DEMUX_SKIP) return 0; + state_bytes -= end - buf; + return iRet; + } + if(!store_mpeg2 (buf, buf + state_bytes, f)) + if(state == DEMUX_SKIP) return 0; + buf += state_bytes; + break; + + case DEMUX_SKIP: + if (demux_pid || (state_bytes > end - buf)) + { + state_bytes -= end - buf; + return iRet; + } + buf += state_bytes; + break; + } + + while (1) + { + if (demux_pid) + { + state = DEMUX_SKIP; + return iRet; + } + + payload_start: + header = buf; + bytes = end - buf; + + continue_header: + NEEDBYTES (4); + if (header[0] || header[1] || (header[2] != 1)) + { + if (demux_pid) + { + state = DEMUX_SKIP; + return iRet; + } + else if (header != head_buf) + { + buf++; + goto payload_start; + } + else + { + header[0] = header[1]; + header[1] = header[2]; + header[2] = header[3]; + bytes = 3; + goto continue_header; + } + } + if (demux_pid) + { + if ((header[3] >= 0xe0) && (header[3] <= 0xef)) + goto pes; + fprintf (stderr, "bad stream id %x\n", header[3]); + return -1; + } + switch (header[3]) + { + case 0xb9: /* program end code */ + /* DONEBYTES (4); */ + /* break; */ + return 1; + + case 0xba: /* pack header */ + NEEDBYTES (12); + if ((header[4] & 0xc0) == 0x40) + { /* mpeg2 */ + NEEDBYTES (14); + len = 14 + (header[13] & 7); + NEEDBYTES (len); + DONEBYTES (len); + /* header points to the mpeg2 pack header */ + } + else if ((header[4] & 0xf0) == 0x20) + { /* mpeg1 */ + DONEBYTES (12); + /* header points to the mpeg1 pack header */ + } + else + { + fprintf (stderr, "weird pack header\n"); + return -1; + } + break; + + case 0xbd: // private stream 1 + case 0xc0: // audio stream 0 + NEEDBYTES (9); + len = header[4]*256+header[5]+6; + NEEDBYTES(len); + DONEBYTES(len); + break; + default: + + if (header[3] == demux_track) + { + pes: + NEEDBYTES (7); + if ((header[6] & 0xc0) == 0x80) + { /* mpeg2 */ + NEEDBYTES (9); + len = 9 + header[8]; + NEEDBYTES (len); + } + else + { /* mpeg1 */ + int len_skip; + len = 7; + while (header[len - 1] == 0xff) + { + len++; + NEEDBYTES (len); + if (len == 23) + { + fprintf (stderr, "too much stuffing\n"); + break; + } + } + if ((header[len - 1] & 0xc0) == 0x40) + { + len += 2; + NEEDBYTES (len); + } + len_skip = len; + len += mpeg1_skip_table[header[len - 1] >> 4]; + NEEDBYTES (len); + } + DONEBYTES (len); + bytes = 6 + (header[4] << 8) + header[5] - len; + if (demux_pid || (bytes > end - buf)) + { + if(!store_mpeg2 (buf, end, f)) + if(state == DEMUX_SKIP) return 0; + state = DEMUX_DATA; + state_bytes = bytes - (end - buf); + return 0; + } + else if (bytes > 0) + { + if(!store_mpeg2 (buf, buf + bytes, f)) + if(state == DEMUX_SKIP) return 0; + buf += bytes; + } + } + else if (header[3] < 0xb9) + { + fprintf (stderr, "looks like a video stream, not system stream\n"); + return -1; + } + else + { + //fprintf(stderr, "header[3] is %02X\n",header[3]); + NEEDBYTES (6); + DONEBYTES (6); + bytes = (header[4] << 8) + header[5]; + //skip: + if (bytes > end - buf) + { + state = DEMUX_SKIP; + state_bytes = bytes - (end - buf); + return iRet; + } + buf += bytes; + } + } + } + + return iRet; +} + +int demuxTS(unsigned char * buffer, unsigned char * end, const char* f, int flags ) +{ + unsigned char * buf; + unsigned char * nextbuf; + unsigned char * data; + int pid; + buf = buffer; + int demuxflag = flags; + int iRet = -1; + + int r = end - buf; + int i = 0; + while( i < r ) + { + if (buf[i] != 0x47) + { + fprintf (stderr, "bad sync byte\n"); + i++; + continue; + } + demux_pid = ((buf[i+1] << 8) + buf[i+2]) & 0x1fff; + i+=188; + } + + for (; (nextbuf = buf + 188) <= end; buf = nextbuf) + { + if (*buf != 0x47) + { + fprintf (stderr, "bad sync byte\n"); + nextbuf = buf + 1; + continue; + } + pid = ((buf[1] << 8) + buf[2]) & 0x1fff; + if (pid != demux_pid) + continue; + data = buf + 4; + if (buf[3] & 0x20) + { // buf contains an adaptation field + data = buf + 5 + buf[4]; + if (data > nextbuf) + continue; + } + if (buf[3] & 0x10) + { + if( (demuxflag & DEMUX_RESET) == DEMUX_RESET ) + { + if( buf[1] & 0x40 ) + { + iRet = demuxPES (data, nextbuf, f, DEMUX_PAYLOAD_START|demuxflag); + if(state == DEMUX_SKIP) return 0; + demuxflag = 0; + } + } + else + { + iRet = demuxPES (data, nextbuf, f, (buf[1] & 0x40) ? DEMUX_PAYLOAD_START|demuxflag : demuxflag); + if(state == DEMUX_SKIP) return 0; + demuxflag = 0; + } + } + } + return iRet; +} diff --git a/contrib/vdr2jpeg/mpegdec.h b/contrib/vdr2jpeg/mpegdec.h new file mode 100644 index 0000000..b28c32d --- /dev/null +++ b/contrib/vdr2jpeg/mpegdec.h @@ -0,0 +1,17 @@ +/* + * Simple program to grab images from VDR Recording + * + * Copyright(c) 2010 Andreas Brachold + * + * This code is distributed under the terms and conditions of the + * GNU GENERAL PUBLIC LICENSE. See the file COPYING for details. + */ + +#ifndef __MPEGDEC_H__ +#define __MPEGDEC_H__ + +void demux_reset(void); +int demuxPES (unsigned char * buf, unsigned char * end, const char* szFileName, int flags); +int demuxTS(unsigned char * buffer, unsigned char * end, const char* szFileName, int flags=0 ); + +#endif diff --git a/contrib/vdr2jpeg/tools.h b/contrib/vdr2jpeg/tools.h index 2911da3..609362e 100644 --- a/contrib/vdr2jpeg/tools.h +++ b/contrib/vdr2jpeg/tools.h @@ -1,7 +1,7 @@ /* * Simple program to grab images from VDR Recording * - * Copyright(c) 2007-2008 Andreas Brachold + * Copyright(c) 2007-2010 Andreas Brachold * * This code is distributed under the terms and conditions of the * GNU GENERAL PUBLIC LICENSE. See the file COPYING for details. @@ -9,22 +9,10 @@ */ #include <string> -#include "ffm.h" int option(int argc, char *argv[], const char opt, bool bParam, std::string & param, int n = 1); -// Helperclass for proper init/deinit ffmpeg -struct ffminit -{ - ffminit() { - ffm_initalize(); - } - - virtual ~ffminit() { - ffm_deinitalize(); - } -}; diff --git a/contrib/vdr2jpeg/vdr2jpeg.cpp b/contrib/vdr2jpeg/vdr2jpeg.cpp index 3c60fc9..f8f7f48 100644 --- a/contrib/vdr2jpeg/vdr2jpeg.cpp +++ b/contrib/vdr2jpeg/vdr2jpeg.cpp @@ -1,7 +1,7 @@ /* * Simple program to grab images from VDR Recording * - * Copyright(c) 2005-2008 Andreas Brachold + * Copyright(c) 2005-2010 Andreas Brachold * * This code is distributed under the terms and conditions of the * GNU GENERAL PUBLIC LICENSE. See the file COPYING for details. @@ -21,8 +21,7 @@ #include "ffm.h" #include "gop.h" - -static const char *VERSION = "0.1.1"; +static const char *VERSION = "0.1.9"; void help(int argc, char *argv[]) { @@ -72,7 +71,8 @@ int main(int argc, char *argv[]) std::vector < int >nFrame; int n = 0; std::string f; -
while(-1 !=(n = option(argc, argv, 'f', true, f, n))) { + + while(-1 !=(n = option(argc, argv, 'f', true, f, n))) { int frame = atoi(f.c_str()); if(frame < 0) { std::cerr << "ignore negative frame" << std::endl << std::endl; @@ -91,22 +91,33 @@ int main(int argc, char *argv[]) return 1; } - std::stringstream ss; - ss << szFolder; - if('/' != *szFolder.rbegin()) - ss << '/'; - ss << "index.vdr"; - ss << std::ends; - std::string szIndex(ss.str()); + static const char* files[] = { "index.vdr", "index" }; struct stat64 ds; - if(stat64(szIndex.c_str(), &ds)) { - std::cerr << "Can't access file : " << szIndex << std::endl; + std::string szIndex; + int nIndexVersion = -1; + for(unsigned int l = 0; l < 2; ++l) { + std::stringstream ss; + ss << szFolder; + if('/' != *szFolder.rbegin()) + ss << '/'; + ss << files[l]; + ss << std::ends; + szIndex = ss.str(); + + if(!stat64(szIndex.c_str(), &ds)) { + nIndexVersion = l; + break; + } + } + if(-1 == nIndexVersion) { + std::cerr << "Can't find index file at " << szFolder << std::endl; return 1; } + int nTotalFrames = (ds.st_size / 8); if(nTotalFrames <= 0) { - std::cerr << "Empty file : " << szIndex << std::endl; + std::cerr << "Empty index file : " << szIndex << std::endl; return 1; } @@ -206,13 +217,14 @@ int main(int argc, char *argv[]) return 0; // Success } #endif //DEBUG - std::vector < std::pair<tFrame,tFrame> > nGOP; - if(ReadIndexFile(szFolder, nFrame, nGOP)) { + if(ReadIndexFile(szIndex, nIndexVersion, nFrame, nGOP)) { ffminit x; - - if(ReadRecordings(szFolder, szOutPath, szTempPath, nGOP, width, height, exact, true)) + if(ReadRecordings(szFolder, nIndexVersion, + szOutPath, szTempPath, + nGOP, width, height, exact, true)) { return 0; // Success + } } return 1; } |
