summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndreas Brachold <vdr07@deltab.de>2010-11-27 13:36:09 +0000
committerAndreas Brachold <vdr07@deltab.de>2010-11-27 13:36:09 +0000
commitf279ccbfdfcaa4e7301b56ade829cb974aeb5636 (patch)
tree2bff18b8a4738140684fa9536fb49a263ab79011
parent1f7ff5d00b83cbeb0afee85042d60aa2e60dbdd0 (diff)
downloadxxv-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/HISTORY2
-rw-r--r--contrib/vdr2jpeg/Makefile26
-rw-r--r--contrib/vdr2jpeg/ffm.h12
-rw-r--r--contrib/vdr2jpeg/gop.cpp313
-rw-r--r--contrib/vdr2jpeg/gop.h61
-rw-r--r--contrib/vdr2jpeg/mpegdec.cpp383
-rw-r--r--contrib/vdr2jpeg/mpegdec.h17
-rw-r--r--contrib/vdr2jpeg/tools.h14
-rw-r--r--contrib/vdr2jpeg/vdr2jpeg.cpp48
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;
}