aboutsummaryrefslogtreecommitdiff
path: root/Src/libvp6/include/NSV_Reader.hpp
diff options
context:
space:
mode:
Diffstat (limited to 'Src/libvp6/include/NSV_Reader.hpp')
-rw-r--r--Src/libvp6/include/NSV_Reader.hpp688
1 files changed, 688 insertions, 0 deletions
diff --git a/Src/libvp6/include/NSV_Reader.hpp b/Src/libvp6/include/NSV_Reader.hpp
new file mode 100644
index 00000000..7521166a
--- /dev/null
+++ b/Src/libvp6/include/NSV_Reader.hpp
@@ -0,0 +1,688 @@
+#if !defined(NSV_READER_HPP)
+#define NSV_READER_HPP
+//______________________________________________________________________________
+//
+// NSV_Reader.hpp
+// NSV Reader Class
+
+#include "NSV.hpp"
+#include "endian.hpp"
+
+#include <string>
+#include <memory>
+#include <fstream>
+#include <sstream>
+#include <cassert>
+
+namespace NSV
+{
+
+ //--------------------------------------
+ // Defines the interface for the basic_Reader template instantiations
+ class Reader_base
+ {
+ public:
+ virtual ~Reader_base()
+ {
+ }
+
+ virtual void open(const std::string& strFile) = 0;
+ virtual void close() = 0;
+
+ virtual File& file() = 0;
+ virtual const std::string& fileName() const = 0;
+
+ virtual void readFileHeader() = 0;
+ virtual void readFrame() = 0;
+ virtual void readFrameInfo() = 0;
+ virtual void readFrameHeader() = 0;
+ virtual void readPayload() = 0;
+ virtual void readPayloadInfo() = 0;
+ virtual void readPayloadHeader(int& nAux, int& iAuxPlusVideo, int& iAudio) = 0;
+
+ virtual void buildIndex(int nIndexEntries) = 0;
+
+ virtual INT64 frames() const = 0;
+ virtual INT64 frame() const = 0;
+ virtual void seek(INT64 nFrame) = 0;
+ virtual void readSample(int nStream, unsigned char* pData, size_t sizeDataMax, size_t& sizeData, bool& bKeyFrame) = 0;
+ virtual bool eof() = 0;
+
+ virtual const FileHeader& fileHeader() const = 0;
+ virtual const FrameHeader& frameHeader() const = 0;
+
+ virtual void* get_ifs() = 0;
+ };
+
+ //--------------------------------------
+ template<typename T>
+ class basic_Reader : public Reader_base
+ {
+ public:
+ basic_Reader(File& f);
+ ~basic_Reader();
+
+ void open(const std::string& strFile);
+ void close();
+
+ File& file();
+ const std::string& fileName() const;
+
+ void readFileHeader();
+ void readFrame();
+ void readFrameInfo();
+ void readFrameHeader();
+ void readPayload();
+ void readPayloadInfo();
+ void readPayloadHeader(int& nAux, int& iAuxPlusVideo, int& iAudio);
+
+ void buildIndex(int nIndexEntries = 0); // index all frames by default
+
+ INT64 frames() const;
+ INT64 frame() const;
+ void seek(INT64 nFrame);
+ void readSample(int nStream, unsigned char* pData, size_t sizeDataMax, size_t& sizeData, bool& bKeyFrame);
+ bool eof();
+
+ const FileHeader& fileHeader() const;
+ const FrameHeader& frameHeader() const;
+
+ void* get_ifs();
+
+ private:
+ basic_Reader(const basic_Reader& r); // Not implemented
+ basic_Reader& operator=(const basic_Reader& r); // Not implemented
+
+ short read_i16();
+ unsigned short read_ui16();
+ int read_i32();
+ unsigned int read_ui32();
+
+ File& m_file;
+ std::string m_strFile;
+ T m_ifs;
+
+ FileHeader m_fileHeader;
+ FrameHeader m_frameHeader;
+ bool m_bFrameHeader;
+
+ INT64 m_nFrame;
+ };
+
+ //--------------------------------------
+ template<typename T>
+ basic_Reader<T>::basic_Reader(File& f) :
+ m_file(f),
+ m_strFile(),
+ m_fileHeader(),
+ m_frameHeader(),
+ m_bFrameHeader(false),
+ m_nFrame(0)
+ {
+ }
+
+ //--------------------------------------
+ template<typename T>
+ basic_Reader<T>::~basic_Reader()
+ {
+ close();
+ }
+
+ //--------------------------------------
+ template<typename T>
+ void basic_Reader<T>::open(const std::string& strFile)
+ {
+ m_strFile = strFile;
+
+ m_ifs.open(m_strFile.c_str(), IOS_BASE::binary);
+ if (!m_ifs)
+ {
+ std::ostringstream ossError;
+ ossError << "Error opening file " << m_strFile;
+ throw Exception(ossError.str());
+ }
+
+ readFileHeader();
+
+ return;
+ }
+
+ //--------------------------------------
+ template<typename T>
+ void basic_Reader<T>::close()
+ {
+ if (m_ifs)
+ {
+ m_ifs.close();
+ }
+
+ m_strFile.erase();
+
+ return;
+ }
+
+ //--------------------------------------
+ template<typename T>
+ File& basic_Reader<T>::file()
+ {
+ return m_file;
+ }
+
+ //--------------------------------------
+ template<typename T>
+ const std::string& basic_Reader<T>::fileName() const
+ {
+ return m_strFile;
+ }
+
+ //--------------------------------------
+ template<typename T>
+ void basic_Reader<T>::readFileHeader()
+ {
+ assert(m_ifs);
+
+ // Read file header signature
+ char cSignature[5];
+ m_ifs.read(cSignature, 4);
+ if (strncmp(cSignature, "NSVf", 4) == 0)
+ {
+ cSignature[4] = '\0';
+ m_fileHeader.m_fccSignature = cSignature;
+ m_fileHeader.m_sizeHeader = read_i32();
+ m_fileHeader.m_sizeFile = read_i32();
+ m_fileHeader.m_iFileSize_ms = read_i32();
+ m_fileHeader.m_sizeMetaData = read_i32();
+ m_fileHeader.m_nTOCAlloc = read_i32();
+ m_fileHeader.m_nTOCSize = read_i32();
+
+ if ((m_fileHeader.m_sizeFile > 0 && m_fileHeader.m_sizeFile < m_fileHeader.m_sizeHeader)
+ || m_fileHeader.m_nTOCSize > m_fileHeader.m_nTOCAlloc)
+ {
+ throw Exception("Invalid NSV file header");
+ }
+
+ if (m_fileHeader.m_sizeMetaData > 0)
+ {
+ std::auto_ptr<char> apcMetaData(new char[m_fileHeader.m_sizeMetaData + 1]);
+ char* pcMetaData = apcMetaData.get();
+ if (pcMetaData == 0)
+ {
+ throw Exception("Out of memory");
+ }
+
+ m_ifs.read(pcMetaData, m_fileHeader.m_sizeMetaData);
+ pcMetaData[m_fileHeader.m_sizeMetaData] = '\0';
+
+ m_file.header(pcMetaData, m_fileHeader.m_nTOCSize);
+ }
+ else
+ {
+ m_file.header("", m_fileHeader.m_nTOCSize);
+ }
+
+ for (int nEntry = 0; nEntry < m_fileHeader.m_nTOCSize; ++nEntry)
+ {
+ POS_TYPE posOffset;
+ posOffset = read_ui32();
+ m_file.indexEntry(nEntry, posOffset);
+ }
+
+ m_ifs.ignore((m_fileHeader.m_nTOCAlloc - m_fileHeader.m_nTOCSize) * 4);
+
+ if (m_ifs.tellg() > static_cast<POS_TYPE>(m_fileHeader.m_sizeHeader))
+ {
+ throw Exception("Invalid NSV file header");
+ }
+
+ m_file.dataOffset(m_fileHeader.m_sizeHeader);
+ m_ifs.seekg(m_file.dataOffset());
+ }
+ else // No file header present
+ {
+ m_fileHeader.m_sizeHeader = 0;
+ m_ifs.seekg(0, IOS_BASE::end);
+ m_fileHeader.m_sizeFile = m_ifs.tellg();
+
+ m_fileHeader.m_iFileSize_ms = 0;
+ m_fileHeader.m_nTOCAlloc = 0;
+ m_file.header("", 0);
+
+ m_file.dataOffset(0);
+ m_ifs.seekg(m_file.dataOffset());
+ }
+
+ // Read stream info from first frame header
+ readFrameHeader();
+ int nAux;
+ int iAuxPlusVideo;
+ int iAudio;
+ readPayloadHeader(nAux, iAuxPlusVideo, iAudio);
+
+ m_file.size(m_frameHeader.m_iWidth, m_frameHeader.m_iHeight);
+ m_file.frameRate(m_frameHeader.m_iFrameRate);
+
+ if (m_fileHeader.m_iFileSize_ms > 0)
+ {
+ INT64 nFramesDenom = static_cast<INT64>(m_file.rateDenom()) * 1000;
+ INT64 nFrames = (static_cast<INT64>(m_fileHeader.m_iFileSize_ms) * static_cast<INT64>(m_file.rateNum()) + nFramesDenom / 2) / nFramesDenom;
+ m_file.frames(nFrames);
+ }
+
+ // Set up primary video and audio streams
+ m_file.newStream(m_frameHeader.m_fccVideo);
+ m_file.newStream(m_frameHeader.m_fccAudio);
+ m_file.stream(0).rate(m_file.rateNum(), m_file.rateDenom());
+ m_file.stream(0).samples(m_file.frames());
+
+ // Set up aux streams
+ for (int n = 0; n < nAux; ++n)
+ {
+ unsigned short uh = read_ui16();
+ unsigned long ul = read_ui32();
+ m_ifs.ignore(uh);
+
+ m_file.newStream(FourCC(ul));
+ // More info ...
+ }
+
+ m_ifs.seekg(m_file.dataOffset());
+
+ return;
+ }
+
+ //--------------------------------------
+ template<typename T>
+ void basic_Reader<T>::readFrame()
+ {
+ readFrameHeader();
+ readPayload();
+
+ return;
+ }
+
+ //--------------------------------------
+ template<typename T>
+ void basic_Reader<T>::readFrameInfo()
+ {
+ readFrameHeader();
+ readPayloadInfo();
+
+ return;
+ }
+
+ //--------------------------------------
+ template<typename T>
+ void basic_Reader<T>::readFrameHeader()
+ {
+ assert(m_ifs);
+
+ // Read frame header signature
+ char cSignature[5];
+ m_ifs.read(cSignature, 2);
+ if (strncmp(cSignature, "\xef\xbe", 2) == 0)
+ {
+ m_frameHeader.m_fccSignature = 0UL;
+ m_frameHeader.m_bKeyFrame = false;
+ m_file.syncOffset(0);
+ return;
+ }
+
+ m_ifs.read(&cSignature[2], 2);
+ if (strncmp(cSignature, "NSVs", 4) != 0)
+ {
+ throw Exception("Invalid NSV frame header");
+ }
+
+ cSignature[4] = '\0';
+ m_frameHeader.m_fccSignature = cSignature;
+ m_ifs.read(reinterpret_cast<char*>(&m_frameHeader.m_fccVideo), 4);
+ m_ifs.read(reinterpret_cast<char*>(&m_frameHeader.m_fccAudio), 4);
+ m_frameHeader.m_iWidth = read_i16();
+ m_frameHeader.m_iHeight = read_i16();
+ unsigned char uc;
+ m_ifs.read(reinterpret_cast<char*>(&uc), 1);
+ m_frameHeader.m_iFrameRate = uc;
+ m_frameHeader.m_iSyncOffset_ms = read_i16();
+ m_frameHeader.m_bKeyFrame = true;
+
+ if (!m_bFrameHeader)
+ {
+// m_file.newStream(m_frameHeader.m_fccVideo);
+// m_file.newStream(m_frameHeader.m_fccAudio);
+// m_file.size(m_frameHeader.m_iWidth, m_frameHeader.m_iHeight);
+// m_file.frameRate(m_frameHeader.m_iFrameRate);
+
+ m_bFrameHeader = true;
+ }
+ else
+ {
+ if ((m_file.streamVideo() >= 0 && m_file.videoFormat() != m_frameHeader.m_fccVideo)
+ || (m_file.streamAudio() >= 0 && m_file.audioFormat() != m_frameHeader.m_fccAudio)
+ || m_file.width() != m_frameHeader.m_iWidth
+ || m_file.height() != m_frameHeader.m_iHeight
+ || m_file.frameRate() != m_frameHeader.m_iFrameRate)
+ {
+ throw Exception("Invalid NSV frame header");
+ }
+ }
+
+ m_file.syncOffset(m_frameHeader.m_iSyncOffset_ms);
+
+ return;
+ }
+
+ //--------------------------------------
+ template<typename T>
+ void basic_Reader<T>::readPayload()
+ {
+ assert(m_ifs);
+
+ int nAux;
+ int iAuxPlusVideo;
+ int iAudio;
+ readPayloadHeader(nAux, iAuxPlusVideo, iAudio);
+
+ int iAux = 0;
+
+ for (int n = 0; n < nAux; ++n)
+ {
+ unsigned short uh = read_ui16();
+ unsigned int ui = read_ui32();
+
+ Stream& s = m_file.stream(m_file.streamAux(n));
+ s.dataSize(uh);
+ m_ifs.read(reinterpret_cast<char*>(s.data()), uh);
+
+ iAux += uh;
+ }
+
+ if (m_file.streamVideo() >= 0)
+ {
+ int iVideo = iAuxPlusVideo - iAux;
+ Stream& sVideo = m_file.stream(m_file.streamVideo());
+ sVideo.dataSize(iVideo);
+ m_ifs.read(reinterpret_cast<char*>(sVideo.data()), iVideo);
+ sVideo.keyFrame(m_frameHeader.m_bKeyFrame);
+ }
+ else
+ {
+ m_ifs.seekg(iAuxPlusVideo - iAux, IOS_BASE::cur);
+ }
+
+ if (m_file.streamAudio() >= 0)
+ {
+ Stream& sAudio = m_file.stream(m_file.streamAudio());
+ sAudio.dataSize(iAudio);
+ m_ifs.read(reinterpret_cast<char*>(sAudio.data()), iAudio);
+ sAudio.keyFrame(true);
+ }
+ else
+ {
+ m_ifs.seekg(iAudio, IOS_BASE::cur);
+ }
+
+ return;
+ }
+
+ //--------------------------------------
+ template<typename T>
+ void basic_Reader<T>::readPayloadInfo()
+ {
+ assert(m_ifs);
+
+ int nAux;
+ int iAuxPlusVideo;
+ int iAudio;
+ readPayloadHeader(nAux, iAuxPlusVideo, iAudio);
+
+ int iAux = 0;
+
+ for (int n = 0; n < nAux; ++n)
+ {
+ unsigned short uh = read_ui16();
+ unsigned int ui = read_ui32();
+ m_ifs.ignore(uh);
+
+ Stream& s = m_file.stream(m_file.streamAux(n));
+ s.dataSize(uh);
+
+ iAux += uh;
+ }
+
+ if (m_file.streamVideo() >= 0)
+ {
+ int iVideo = iAuxPlusVideo - iAux;
+ Stream& sVideo = m_file.stream(m_file.streamVideo());
+ sVideo.dataSize(iVideo);
+ sVideo.keyFrame(m_frameHeader.m_bKeyFrame);
+ }
+
+ if (m_file.streamAudio() >= 0)
+ {
+ Stream& sAudio = m_file.stream(m_file.streamAudio());
+ sAudio.dataSize(iAudio);
+ sAudio.keyFrame(true);
+ }
+
+ return;
+ }
+
+ //--------------------------------------
+ template<typename T>
+ void basic_Reader<T>::readPayloadHeader(int& nAux, int& iAuxPlusVideo, int& iAudio)
+ {
+ assert(m_ifs);
+
+ char c;
+ unsigned short uh;
+ unsigned short uhAudio;
+
+ m_ifs.get(c);
+ uh = read_ui16();
+ uhAudio = read_ui16();
+
+ nAux = c & 0xf;
+ iAuxPlusVideo = (static_cast<int>(uh) << 4) | ((c >> 4) & 0xf);
+ iAudio = uhAudio;
+
+ return;
+ }
+
+ //--------------------------------------
+ template<typename T>
+ void basic_Reader<T>::buildIndex(int nIndexEntries)
+ {
+ assert(nIndexEntries == 0); // Only creates full index for now ...
+
+ m_file.index().clear();
+ m_file.frames(0);
+
+ m_ifs.seekg(m_file.dataOffset());
+
+ INT64 nFrames = 0;
+ for (; !eof(); ++nFrames)
+ {
+ m_file.appendIndexEntry(static_cast<POS_TYPE>(m_ifs.tellg()) - m_file.dataOffset());
+
+ readFrameHeader();
+ int nAux;
+ int iAuxPlusVideo;
+ int iAudio;
+ readPayloadHeader(nAux, iAuxPlusVideo, iAudio);
+ m_ifs.seekg(iAuxPlusVideo + iAudio, IOS_BASE::cur);
+ }
+
+ m_file.frames(nFrames);
+
+ m_ifs.seekg(m_file.dataOffset());
+
+ return;
+ }
+
+ //--------------------------------------
+ template<typename T>
+ INT64 basic_Reader<T>::frames() const
+ {
+ return m_file.frames();
+ }
+
+ //--------------------------------------
+ template<typename T>
+ INT64 basic_Reader<T>::frame() const
+ {
+ return m_nFrame;
+ }
+
+ //--------------------------------------
+ template<typename T>
+ void basic_Reader<T>::seek(INT64 nFrame)
+ {
+ assert(m_ifs);
+ INT64 nFrames = m_file.frames();
+ assert(nFrame < nFrames || nFrames == -1);
+
+ int nIndexEntries = m_file.index().size();
+
+ if (nIndexEntries > 0)
+ {
+ int nIndexEntry = nIndexEntries * nFrame / nFrames;
+ INT64 nFrameIndex = (nIndexEntry * nFrames + nIndexEntries / 2) / nIndexEntries;
+
+ m_ifs.seekg(m_file.dataOffset() + m_file.index()[nIndexEntry].m_posOffset);
+
+ for (; nFrameIndex < nFrame; ++nFrameIndex)
+ {
+ readFrameHeader();
+ int nAux;
+ int iAuxPlusVideo;
+ int iAudio;
+ readPayloadHeader(nAux, iAuxPlusVideo, iAudio);
+ m_ifs.seekg(iAuxPlusVideo + iAudio, IOS_BASE::cur);
+ }
+
+ m_nFrame = nFrame;
+ }
+ else
+ {
+ m_ifs.seekg(m_file.dataOffset());
+
+ for (m_nFrame = 0; m_nFrame < nFrame; ++m_nFrame)
+ {
+ readFrameHeader();
+ int nAux;
+ int iAuxPlusVideo;
+ int iAudio;
+ readPayloadHeader(nAux, iAuxPlusVideo, iAudio);
+ m_ifs.seekg(iAuxPlusVideo + iAudio, IOS_BASE::cur);
+ }
+
+ assert(m_nFrame == nFrame);
+ }
+
+ return;
+ }
+
+ //--------------------------------------
+ template<typename T>
+ void basic_Reader<T>::readSample(int nStream, unsigned char* pData, size_t sizeDataMax, size_t& sizeData, bool& bKeyFrame)
+ {
+ assert(m_ifs);
+ assert(pData != 0);
+
+ readFrame();
+
+ Stream& s = m_file.stream(nStream);
+
+ size_t size = s.dataSize();
+ if (sizeDataMax < s.dataSize())
+ {
+ size = sizeDataMax;
+ }
+
+ memcpy(pData, s.data(), size);
+ sizeData = s.dataSize();
+
+ bKeyFrame = s.keyFrame();
+
+ return;
+ }
+
+ //--------------------------------------
+ template<typename T>
+ bool basic_Reader<T>::eof()
+ {
+ return m_ifs.tellg() >= m_fileHeader.m_sizeFile;
+ }
+
+ //--------------------------------------
+ template<typename T>
+ const FileHeader& basic_Reader<T>::fileHeader() const
+ {
+ return m_fileHeader;
+ }
+
+ //--------------------------------------
+ template<typename T>
+ const FrameHeader& basic_Reader<T>::frameHeader() const
+ {
+ return m_frameHeader;
+ }
+
+ //--------------------------------------
+ template<typename T>
+ void* basic_Reader<T>::get_ifs()
+ {
+ return &m_ifs;
+ }
+
+ //--------------------------------------
+ template<typename T>
+ short basic_Reader<T>::read_i16()
+ {
+ assert(m_ifs);
+
+ short i16;
+ m_ifs.read(reinterpret_cast<char*>(&i16), 2);
+
+ return native_endian(i16, false);
+ }
+
+ //--------------------------------------
+ template<typename T>
+ unsigned short basic_Reader<T>::read_ui16()
+ {
+ assert(m_ifs);
+
+ unsigned short ui16;
+ m_ifs.read(reinterpret_cast<char*>(&ui16), 2);
+
+ return native_endian(ui16, false);
+ }
+
+ //--------------------------------------
+ template<typename T>
+ int basic_Reader<T>::read_i32()
+ {
+ assert(m_ifs);
+
+ int i32;
+ m_ifs.read(reinterpret_cast<char*>(&i32), 4);
+
+ return native_endian(i32, false);
+ }
+
+ //--------------------------------------
+ template<typename T>
+ unsigned int basic_Reader<T>::read_ui32()
+ {
+ assert(m_ifs);
+
+ unsigned int ui32;
+ m_ifs.read(reinterpret_cast<char*>(&ui32), 4);
+
+ return native_endian(ui32, false);
+ }
+
+} // namespace NSV
+
+#endif // NSV_READER_HPP