123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688 |
- #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
|