mirror of
https://github.com/opencv/opencv.git
synced 2024-11-25 03:30:34 +08:00
AVI container: use C++ streams for file operations, check some operations for overflow
This commit is contained in:
parent
4a3dfffd46
commit
53eb27f508
@ -153,7 +153,7 @@ public:
|
||||
bool initContainer(const String& filename, double fps, Size size, bool iscolor);
|
||||
void startWriteAVI(int stream_count);
|
||||
void writeStreamHeader(Codecs codec_);
|
||||
void startWriteChunk(int fourcc);
|
||||
void startWriteChunk(uint32_t fourcc);
|
||||
void endWriteChunk();
|
||||
|
||||
int getAVIIndex(int stream_number, StreamType strm_type);
|
||||
|
@ -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())
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user