|
|
|
@ -3,10 +3,29 @@ |
|
|
|
|
// of this distribution and at http://opencv.org/license.html.
|
|
|
|
|
|
|
|
|
|
#include "opencv2/videoio/container_avi.private.hpp" |
|
|
|
|
#include <fstream> |
|
|
|
|
#include <limits> |
|
|
|
|
#include <typeinfo> |
|
|
|
|
|
|
|
|
|
namespace cv |
|
|
|
|
{ |
|
|
|
|
|
|
|
|
|
// Utility function for safe integer conversions
|
|
|
|
|
template <typename D, typename S> |
|
|
|
|
inline D safe_int_cast(S val) |
|
|
|
|
{ |
|
|
|
|
typedef std::numeric_limits<S> st; |
|
|
|
|
typedef std::numeric_limits<D> dt; |
|
|
|
|
CV_StaticAssert(st::is_integer && dt::is_integer, "Integer type is expected"); |
|
|
|
|
const bool in_range_r = (double)val <= (double)dt::max(); |
|
|
|
|
const bool in_range_l = (double)val >= (double)dt::min(); |
|
|
|
|
if (!in_range_r || !in_range_l) |
|
|
|
|
{ |
|
|
|
|
CV_Error_(cv::Error::StsOutOfRange, ("Can not convert integer values (%s -> %s), value 0x%llx is out of range", typeid(S).name(), typeid(D).name(), val)); |
|
|
|
|
} |
|
|
|
|
return static_cast<D>(val); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
const uint32_t RIFF_CC = CV_FOURCC('R','I','F','F'); |
|
|
|
|
const uint32_t LIST_CC = CV_FOURCC('L','I','S','T'); |
|
|
|
|
const uint32_t HDRL_CC = CV_FOURCC('h','d','r','l'); |
|
|
|
@ -116,12 +135,15 @@ public: |
|
|
|
|
bool open(const String& filename); |
|
|
|
|
void close(); |
|
|
|
|
operator bool(); |
|
|
|
|
VideoInputStream& operator=(const VideoInputStream& stream); |
|
|
|
|
|
|
|
|
|
private: |
|
|
|
|
VideoInputStream(const VideoInputStream&); |
|
|
|
|
VideoInputStream& operator=(const VideoInputStream&); |
|
|
|
|
|
|
|
|
|
private: |
|
|
|
|
std::ifstream input; |
|
|
|
|
bool m_is_valid; |
|
|
|
|
String m_fname; |
|
|
|
|
FILE* m_f; |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
#pragma pack(pop) |
|
|
|
@ -174,12 +196,12 @@ String fourccToString(uint32_t fourcc) |
|
|
|
|
return format("%c%c%c%c", fourcc & 255, (fourcc >> 8) & 255, (fourcc >> 16) & 255, (fourcc >> 24) & 255); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
VideoInputStream::VideoInputStream(): m_is_valid(false), m_f(0) |
|
|
|
|
VideoInputStream::VideoInputStream(): m_is_valid(false) |
|
|
|
|
{ |
|
|
|
|
m_fname = String(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
VideoInputStream::VideoInputStream(const String& filename): m_is_valid(false), m_f(0) |
|
|
|
|
VideoInputStream::VideoInputStream(const String& filename): m_is_valid(false) |
|
|
|
|
{ |
|
|
|
|
m_fname = filename; |
|
|
|
|
open(filename); |
|
|
|
@ -187,17 +209,14 @@ VideoInputStream::VideoInputStream(const String& filename): m_is_valid(false), m |
|
|
|
|
|
|
|
|
|
bool VideoInputStream::isOpened() const |
|
|
|
|
{ |
|
|
|
|
return m_f != 0; |
|
|
|
|
return input.is_open(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
bool VideoInputStream::open(const String& filename) |
|
|
|
|
{ |
|
|
|
|
close(); |
|
|
|
|
|
|
|
|
|
m_f = fopen(filename.c_str(), "rb"); |
|
|
|
|
|
|
|
|
|
input.open(filename.c_str(), std::ios_base::binary); |
|
|
|
|
m_is_valid = isOpened(); |
|
|
|
|
|
|
|
|
|
return m_is_valid; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -206,9 +225,7 @@ void VideoInputStream::close() |
|
|
|
|
if(isOpened()) |
|
|
|
|
{ |
|
|
|
|
m_is_valid = false; |
|
|
|
|
|
|
|
|
|
fclose(m_f); |
|
|
|
|
m_f = 0; |
|
|
|
|
input.close(); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -216,7 +233,8 @@ VideoInputStream& VideoInputStream::read(char* buf, uint64_t count) |
|
|
|
|
{ |
|
|
|
|
if(isOpened()) |
|
|
|
|
{ |
|
|
|
|
m_is_valid = (count == fread((void*)buf, 1, (size_t)count, m_f)); |
|
|
|
|
input.read(buf, safe_int_cast<std::streamsize>(count)); |
|
|
|
|
m_is_valid = (input.gcount() == (std::streamsize)count); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return *this; |
|
|
|
@ -224,14 +242,15 @@ VideoInputStream& VideoInputStream::read(char* buf, uint64_t count) |
|
|
|
|
|
|
|
|
|
VideoInputStream& VideoInputStream::seekg(uint64_t pos) |
|
|
|
|
{ |
|
|
|
|
m_is_valid = (fseek(m_f, (int32_t)pos, SEEK_SET) == 0); |
|
|
|
|
|
|
|
|
|
input.clear(); |
|
|
|
|
input.seekg(safe_int_cast<std::streamoff>(pos)); |
|
|
|
|
m_is_valid = !input.eof(); |
|
|
|
|
return *this; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
uint64_t VideoInputStream::tellg() |
|
|
|
|
{ |
|
|
|
|
return ftell(m_f); |
|
|
|
|
return input.tellg(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
VideoInputStream::operator bool() |
|
|
|
@ -239,16 +258,6 @@ VideoInputStream::operator bool() |
|
|
|
|
return m_is_valid; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
VideoInputStream& VideoInputStream::operator=(const VideoInputStream& stream) |
|
|
|
|
{ |
|
|
|
|
if (this != &stream) { |
|
|
|
|
m_fname = stream.m_fname; |
|
|
|
|
// m_f = stream.m_f;
|
|
|
|
|
open(m_fname); |
|
|
|
|
} |
|
|
|
|
return *this; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
VideoInputStream::~VideoInputStream() |
|
|
|
|
{ |
|
|
|
|
close(); |
|
|
|
@ -591,7 +600,7 @@ public: |
|
|
|
|
~BitStream() { close(); } |
|
|
|
|
|
|
|
|
|
bool open(const String& filename); |
|
|
|
|
bool isOpened() const { return m_f != 0; } |
|
|
|
|
bool isOpened() const { return output.is_open(); } |
|
|
|
|
void close(); |
|
|
|
|
|
|
|
|
|
void writeBlock(); |
|
|
|
@ -600,20 +609,24 @@ public: |
|
|
|
|
void putBytes(const uchar* buf, int count); |
|
|
|
|
|
|
|
|
|
void putShort(int val); |
|
|
|
|
void putInt(int val); |
|
|
|
|
void putInt(uint32_t val); |
|
|
|
|
void jputShort(int val); |
|
|
|
|
void patchInt(int val, size_t pos); |
|
|
|
|
void patchInt(uint32_t val, size_t pos); |
|
|
|
|
void jput(unsigned currval); |
|
|
|
|
void jflush(unsigned currval, int bitIdx); |
|
|
|
|
|
|
|
|
|
private: |
|
|
|
|
BitStream(const BitStream &); |
|
|
|
|
BitStream &operator=(const BitStream&); |
|
|
|
|
|
|
|
|
|
protected: |
|
|
|
|
std::ofstream output; |
|
|
|
|
std::vector<uchar> m_buf; |
|
|
|
|
uchar* m_start; |
|
|
|
|
uchar* m_end; |
|
|
|
|
uchar* m_current; |
|
|
|
|
size_t m_pos; |
|
|
|
|
bool m_is_opened; |
|
|
|
|
FILE* m_f; |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
static const size_t DEFAULT_BLOCK_SIZE = (1 << 15); |
|
|
|
@ -624,7 +637,6 @@ BitStream::BitStream() |
|
|
|
|
m_start = &m_buf[0]; |
|
|
|
|
m_end = m_start + DEFAULT_BLOCK_SIZE; |
|
|
|
|
m_is_opened = false; |
|
|
|
|
m_f = 0; |
|
|
|
|
m_current = 0; |
|
|
|
|
m_pos = 0; |
|
|
|
|
} |
|
|
|
@ -632,9 +644,7 @@ BitStream::BitStream() |
|
|
|
|
bool BitStream::open(const String& filename) |
|
|
|
|
{ |
|
|
|
|
close(); |
|
|
|
|
m_f = fopen(filename.c_str(), "wb"); |
|
|
|
|
if( !m_f ) |
|
|
|
|
return false; |
|
|
|
|
output.open(filename.c_str(), std::ios_base::binary); |
|
|
|
|
m_current = m_start; |
|
|
|
|
m_pos = 0; |
|
|
|
|
return true; |
|
|
|
@ -643,25 +653,22 @@ bool BitStream::open(const String& filename) |
|
|
|
|
void BitStream::close() |
|
|
|
|
{ |
|
|
|
|
writeBlock(); |
|
|
|
|
if( m_f ) |
|
|
|
|
fclose(m_f); |
|
|
|
|
m_f = 0; |
|
|
|
|
output.close(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void BitStream::writeBlock() |
|
|
|
|
{ |
|
|
|
|
size_t wsz0 = m_current - m_start; |
|
|
|
|
if( wsz0 > 0 && m_f ) |
|
|
|
|
ptrdiff_t wsz0 = m_current - m_start; |
|
|
|
|
if( wsz0 > 0 ) |
|
|
|
|
{ |
|
|
|
|
size_t wsz = fwrite(m_start, 1, wsz0, m_f); |
|
|
|
|
CV_Assert( wsz == wsz0 ); |
|
|
|
|
output.write((char*)m_start, wsz0); |
|
|
|
|
} |
|
|
|
|
m_pos += wsz0; |
|
|
|
|
m_current = m_start; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
size_t BitStream::getPos() const { |
|
|
|
|
return (size_t)(m_current - m_start) + m_pos; |
|
|
|
|
return safe_int_cast<size_t>(m_current - m_start) + m_pos; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void BitStream::putByte(int val) |
|
|
|
@ -674,7 +681,7 @@ void BitStream::putByte(int val) |
|
|
|
|
void BitStream::putBytes(const uchar* buf, int count) |
|
|
|
|
{ |
|
|
|
|
uchar* data = (uchar*)buf; |
|
|
|
|
CV_Assert(m_f && data && m_current && count >= 0); |
|
|
|
|
CV_Assert(data && m_current && count >= 0); |
|
|
|
|
if( m_current >= m_end ) |
|
|
|
|
writeBlock(); |
|
|
|
|
|
|
|
|
@ -706,7 +713,7 @@ void BitStream::putShort(int val) |
|
|
|
|
writeBlock(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void BitStream::putInt(int val) |
|
|
|
|
void BitStream::putInt(uint32_t val) |
|
|
|
|
{ |
|
|
|
|
m_current[0] = (uchar)val; |
|
|
|
|
m_current[1] = (uchar)(val >> 8); |
|
|
|
@ -726,11 +733,11 @@ void BitStream::jputShort(int val) |
|
|
|
|
writeBlock(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void BitStream::patchInt(int val, size_t pos) |
|
|
|
|
void BitStream::patchInt(uint32_t val, size_t pos) |
|
|
|
|
{ |
|
|
|
|
if( pos >= m_pos ) |
|
|
|
|
{ |
|
|
|
|
ptrdiff_t delta = pos - m_pos; |
|
|
|
|
ptrdiff_t delta = safe_int_cast<ptrdiff_t>(pos - m_pos); |
|
|
|
|
CV_Assert( delta < m_current - m_start ); |
|
|
|
|
m_start[delta] = (uchar)val; |
|
|
|
|
m_start[delta+1] = (uchar)(val >> 8); |
|
|
|
@ -739,12 +746,11 @@ void BitStream::patchInt(int val, size_t pos) |
|
|
|
|
} |
|
|
|
|
else |
|
|
|
|
{ |
|
|
|
|
CV_Assert(pos < (1u<<31)); |
|
|
|
|
long fpos = ftell(m_f); |
|
|
|
|
fseek(m_f, (long)pos, SEEK_SET); |
|
|
|
|
std::streamoff fpos = output.tellp(); |
|
|
|
|
output.seekp(safe_int_cast<std::streamoff>(pos)); |
|
|
|
|
uchar buf[] = { (uchar)val, (uchar)(val >> 8), (uchar)(val >> 16), (uchar)(val >> 24) }; |
|
|
|
|
fwrite(buf, 1, 4, m_f); |
|
|
|
|
fseek(m_f, fpos, SEEK_SET); |
|
|
|
|
output.write((char *)buf, 4); |
|
|
|
|
output.seekp(fpos); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -876,7 +882,7 @@ void AVIWriteContainer::writeStreamHeader(Codecs codec_) |
|
|
|
|
|
|
|
|
|
strm->putInt(0); |
|
|
|
|
strm->putInt(SUG_BUFFER_SIZE); |
|
|
|
|
strm->putInt(AVI_DWQUALITY); |
|
|
|
|
strm->putInt(static_cast<uint32_t>(AVI_DWQUALITY)); |
|
|
|
|
strm->putInt(0); |
|
|
|
|
strm->putShort(0); |
|
|
|
|
strm->putShort(0); |
|
|
|
@ -935,7 +941,7 @@ void AVIWriteContainer::writeStreamHeader(Codecs codec_) |
|
|
|
|
strm->putInt(MOVI_CC); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void AVIWriteContainer::startWriteChunk(int fourcc) |
|
|
|
|
void AVIWriteContainer::startWriteChunk(uint32_t fourcc) |
|
|
|
|
{ |
|
|
|
|
CV_Assert(fourcc != 0); |
|
|
|
|
strm->putInt(fourcc); |
|
|
|
@ -949,9 +955,12 @@ void AVIWriteContainer::endWriteChunk() |
|
|
|
|
if( !AVIChunkSizeIndex.empty() ) |
|
|
|
|
{ |
|
|
|
|
size_t currpos = strm->getPos(); |
|
|
|
|
CV_Assert(currpos > 4); |
|
|
|
|
currpos -= 4; |
|
|
|
|
size_t pospos = AVIChunkSizeIndex.back(); |
|
|
|
|
AVIChunkSizeIndex.pop_back(); |
|
|
|
|
int chunksz = (int)(currpos - (pospos + 4)); |
|
|
|
|
CV_Assert(currpos >= pospos); |
|
|
|
|
uint32_t chunksz = safe_int_cast<uint32_t>(currpos - pospos); |
|
|
|
|
strm->patchInt(chunksz, pospos); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
@ -966,8 +975,8 @@ int AVIWriteContainer::getAVIIndex(int stream_number, StreamType strm_type) { |
|
|
|
|
case dc: return CV_FOURCC(strm_indx[0], strm_indx[1], 'd', 'c'); |
|
|
|
|
case pc: return CV_FOURCC(strm_indx[0], strm_indx[1], 'p', 'c'); |
|
|
|
|
case wb: return CV_FOURCC(strm_indx[0], strm_indx[1], 'w', 'b'); |
|
|
|
|
default: return CV_FOURCC(strm_indx[0], strm_indx[1], 'd', 'b'); |
|
|
|
|
} |
|
|
|
|
return CV_FOURCC(strm_indx[0], strm_indx[1], 'd', 'b'); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void AVIWriteContainer::writeIndex(int stream_number, StreamType strm_type) |
|
|
|
@ -987,7 +996,7 @@ void AVIWriteContainer::writeIndex(int stream_number, StreamType strm_type) |
|
|
|
|
|
|
|
|
|
void AVIWriteContainer::finishWriteAVI() |
|
|
|
|
{ |
|
|
|
|
int nframes = (int)frameOffset.size(); |
|
|
|
|
uint32_t nframes = safe_int_cast<uint32_t>(frameOffset.size()); |
|
|
|
|
// Record frames numbers to AVI Header
|
|
|
|
|
while (!frameNumIndexes.empty()) |
|
|
|
|
{ |
|
|
|
|