winamp/Src/libvp6/include/AVI.hpp
2024-09-24 14:54:57 +02:00

985 lines
22 KiB
C++

//=====================================================================
//
// Copyright (c) 1999-2003 On2 Technologies Inc. All Rights Reserved.
//
//---------------------------------------------------------------------
//
// File: $Workfile: AVI.hpp$
//
// Date: $Date: 2010/07/23 19:10:47 $
//
// Revision: $Revision: 1.1 $
//
//---------------------------------------------------------------------
#ifndef AVI_HPP
#define AVI_HPP
#pragma warning(disable:4786)
#include "FourCC.hpp"
#include <exception>
#include <iosfwd>
#include <list>
#include <deque>
#include <string>
#include <vector>
#if defined WIN32
#include <windows.h>
#endif
namespace AVI
{
#if defined WIN32
typedef unsigned __int64 size_type;
typedef DWORD dword;
typedef __int64 offset_t;
typedef unsigned __int32 length_t;
#elif defined LINUX
typedef unsigned long long size_type;
typedef unsigned long dword;
typedef long long offset_t;
typedef unsigned int length_t;
#endif
int asStreamId(const FourCC&);
enum ChunkType
{
waveform,
waveform_encrypted,
DIB_compressed,
DIB_uncompressed,
DIB_encrypted,
kChunkTypeUnknown
};
ChunkType asChunkType(const FourCC&);
const FourCC asChunkId(int stream, ChunkType type);
const FourCC asIndexChunkExId(int stream);
size_type estimatedFileSize(
int width,
int height,
int frameCount);
const std::string offtoa(offset_t);
class FileError : public std::exception
{
public:
FileError(dword messageId);
FileError(const char* message);
~FileError() throw();
const char* what() const throw();
dword id() const;
private:
std::string message;
dword m_id;
};
struct MainHeader
{
enum Flag
{
hasIndex = 0x00000010,
mustUseIndex = 0x00000020,
isInterleaved = 0x00000100,
indexIsAbsolute = 0x00000800, //? "trust cktype"
wasCaptureFile = 0x00010000,
copyrighted = 0x00020000
};
dword microSecPerFrame;
dword maxBytesPerSec;
dword paddingGranularity;
dword flags;
dword totalFrames;
dword initialFrames;
dword streams;
dword suggestedBufferSize;
dword width;
dword height;
dword reserved[4];
const std::string flagsAsStr() const;
};
std::ostream& operator<<(std::ostream&, const MainHeader&);
class Chunk
{
public:
Chunk(const FourCC, length_t, const unsigned char* data = 0);
const FourCC fcc() const;
length_t length() const;
const unsigned char* data() const;
unsigned char* data();
void data(const unsigned char* d);
private:
FourCC m_fcc;
// length_t m_length;
// unsigned char* m_data;
typedef std::vector<unsigned char> data_t;
data_t m_data;
};
std::ostream& operator<<(std::ostream& os, const Chunk&);
typedef std::vector<Chunk> ExtraHeaderVector;
struct Rectangle
{
typedef unsigned short T;
T left;
T top;
T right;
T bottom;
Rectangle()
: left(0), top(0), right(0), bottom(0)
{
}
Rectangle(T l, T t, T r, T b)
: left(l), top(t), right(r), bottom(b)
{
}
};
struct StreamHeader
{
enum Flag
{
disabled = 0x00000001,
formatChanges = 0x00010000
};
FourCC fccType;
FourCC fccHandler;
dword flags;
unsigned short priority;
unsigned short language;
dword initialFrames;
dword scale;
dword rate;
dword start;
dword length;
dword suggestedBufferSize;
long quality;
dword sampleSize;
Rectangle frame;
const std::string flagsAsStr() const;
};
std::ostream& operator<<(std::ostream&, const StreamHeader&);
struct BitmapInfoHeader
{
dword size;
long width;
long height;
unsigned short planes;
unsigned short bitCount;
FourCC compression;
dword sizeImage;
long xPelsPerMeter;
long yPelsPerMeter;
dword clrUsed;
dword clrImportant;
};
std::ostream& operator<<(std::ostream&, const BitmapInfoHeader&);
// namespace Compression
// {
// enum CompressionType
// {
// RGB,
// RLE8,
// RLE4,
// bitfields,
// unknown
// };
//
// bool operator==(CompressionType, const FourCC&);
// bool operator==(const FourCC&, CompressionType);
//
// CompressionType asCompression(const FourCC&);
// const FourCC asFourCC(CompressionType);
//
// std::ostream& operator<<(std::ostream&, CompressionType);
// }
struct PCMWaveFormat
{
unsigned short formatTag;
unsigned short nChannels;
dword samplesPerSec;
dword avgBytesPerSec;
unsigned short blockAlign;
unsigned short bitsPerSample;
};
struct WaveFormatEx : public PCMWaveFormat
{
typedef std::vector<unsigned char> ByteArray;
ByteArray extra;
};
std::ostream& operator<<(std::ostream&, const WaveFormatEx&);
//not currently used; it's for palette changes,
//which isn't implemented yet
struct RGBQuad
{
unsigned char blue;
unsigned char green;
unsigned char red;
unsigned char reserved;
};
struct IndexEntry
{
enum Flags
{
list = 0x00000001,
keyframe = 0x00000010,
notime = 0x00000100,
compuse = 0x0FFF0000
};
FourCC chunkId;
dword flags;
dword chunkOffset;
dword chunkLength;
const std::string flagsAsStr() const;
};
std::ostream& operator<<(std::ostream&, const IndexEntry&);
typedef std::vector<IndexEntry> IEVector;
struct FrameIndexEntry
{
union
{
offset_t offset;
struct
{
unsigned long offset_low;
unsigned long offset_high;
};
};
size_t size;
bool keyframe;
};
typedef std::vector<FrameIndexEntry> FrameIEVector;
typedef std::list<FrameIndexEntry> FrameIEList;
typedef std::deque<FrameIndexEntry> FrameIndex;
struct IndexChunkEx
{
FourCC code;
unsigned long length;
unsigned short longsPerEntry;
unsigned char subtype;
unsigned char type;
unsigned long entriesInUse;
FourCC chunkId;
unsigned long reserved[3];
};
std::ostream& operator<<(std::ostream&, const IndexChunkEx&);
struct StandardIndexChunk
{
FourCC code;
unsigned long length;
unsigned short longsPerEntry;
unsigned char subtype;
unsigned char type;
unsigned long entriesInUse;
FourCC chunkId;
unsigned long baseOffset_low;
unsigned long baseOffset_high;
unsigned long reserved;
struct Entry
{
unsigned long offset;
unsigned long size;
} index[1];
};
std::ostream& operator<<(std::ostream&, const StandardIndexChunk&);
std::ostream& operator<<(std::ostream&, const StandardIndexChunk::Entry&);
struct SuperIndexChunk
{
FourCC code;
unsigned long length;
unsigned short longsPerEntry;
unsigned char subtype;
unsigned char type;
unsigned long entriesInUse;
FourCC chunkId;
unsigned long reserved[3];
struct Entry
{
offset_t offset;
unsigned long size;
unsigned long duration;
} index[1];
};
std::ostream& operator<<(std::ostream&, const SuperIndexChunk&);
std::ostream& operator<<(std::ostream&, const SuperIndexChunk::Entry&);
class File
{
public:
enum mode_t {in, out, inout};
enum OutputType
{
OT_AVI,
OT_On2
};
File();
File(const char* name, mode_t mode);
~File();
void open(const char* name, mode_t mode, dword flags = 0);
void outputType(OutputType ot);
void close();
bool isOpen() const;
mode_t mode() const;
const char* name() const;
void mapinit();
void mapfinal();
unsigned long map(
offset_t offset,
length_t size,
unsigned char*& base,
length_t& baseSize,
length_t& offsetInView) const;
void unmap(unsigned char* base, length_t size) const;
const MainHeader& mainHeader() const;
MainHeader& mainHeader();
int extraHeaderCount() const;
const Chunk& extraHeader(int nChunk) const;
void extraHeader(FourCC fcc, length_t length, unsigned char* data);
void extraHeader(int nStream, FourCC fcc, length_t length, unsigned char* data);
dword totalFrames() const;
dword& totalFrames();
int streamCount() const;
int makeStreamHeaderVideo(int superIndexEntryCount = 0);
int makeStreamHeaderAudio(int superIndexEntryCount = 0);
const StreamHeader& streamHeader(int stream) const;
StreamHeader& streamHeader(int stream);
const unsigned char* strf(int nStream) const;
size_t strfSize(int nStream) const;
const BitmapInfoHeader& videoFormat(int stream) const;
BitmapInfoHeader& videoFormat(int stream);
const WaveFormatEx& audioFormat(int stream) const;
WaveFormatEx& audioFormat(int stream);
dword streamDataSize(int stream) const;
const unsigned char* streamData(int stream) const;
void setStreamData(int nStream, dword sds, const unsigned char* psd);
const char* streamName(int stream) const;
void setStreamName(int nStream, const char* psn);
SuperIndexChunk& superIndexChunk(int stream);
const SuperIndexChunk& superIndexChunk(int stream) const;
int superIndexEntryCount(int stream) const;
offset_t tell() const;
void seek(offset_t) const;
void seekCurrent(offset_t) const;
offset_t dataOffset() const;
offset_t idx1Offset() const;
length_t idx1Size() const;
void rewriteHeaders();
//For use by header updaters, throws if position of movi list
//changes, positions at beginning of data.
void seekMainHeader();
void writeMainHeader();
length_t seekStreamHeader(int stream);
void writeStreamHeader(int stream);
void seekVideoFormat(int stream);
void writeVideoFormat(int stream);
void seekAudioFormat(int stream);
void writeAudioFormat(int stream);
void seekStreamData(int stream);
void writeStreamData(int stream);
void seekSuperIndexChunk(int stream);
void writeSuperIndexChunk(int stream);
int indexCount() const;
void seekIndex() const;
void read(IndexEntry&) const;
void load(int stream, IEVector& index) const;
void load(int stream, FrameIndex& index) const;
void loadIndex(int, FrameIndex&) const;
void loadIndexEx(int, FrameIndex&) const;
void writeIndexChunkHeader(int number_of_index_entries);
void write(const IndexEntry&) const;
void writeIndexChunk(const IEVector& index);
void writeIndexChunk(
const FourCC& chunkId,
const FrameIndex& index);
void writeStandardIndexChunk(
int stream,
const FrameIndex& index,
offset_t baseOffset);
void writeStandardIndexChunk(
int stream,
const FrameIndex& index);
size_t makeSegment();
int segmentCount() const;
offset_t segmentOffset() const;
const FourCC readFourCC() const;
void writeFourCC(const FourCC&);
const FourCC testFourCC() const;
length_t readLength() const;
void writeLength(length_t length);
void read(void* buffer, size_t size) const;
void write(const void* data, size_t size, bool adjust = true);
void writeJunkChunk(length_t);
int countIndexEntries(int stream) const;
bool indexIsRelative() const;
offset_t size() const;
private:
File(const File& rhs);
File& operator=(const File& rhs);
//void readUnknownChunk() const;
void readJunkChunk() const;
bool readInit();
bool readHeaderList();
void readMainHeader();
void readExtraHeaders();
void readStreamHeaderList();
void readStreamHeader(StreamHeader& h);
void readStreamVideoFormat(BitmapInfoHeader& f);
struct StreamInfoVideo;
void readStreamVideoFormat(StreamInfoVideo* psiv);
void readStreamAudioFormat(WaveFormatEx& f);
void readStreamName(std::string& name);
void readExtendedAVIHeader();
void writeExtendedAVIHeader();
bool readDataList();
void readDataRecChunk() const;
void readDataChunk() const;
void readIndexList();
void writeInit();
void writeFinal();
void writeHeader();
void writeStreamHeaderList(int stream);
void writeStreamHeader(const StreamHeader& h);
void writeStreamVideoFormatChunk(const BitmapInfoHeader& f);
void writeStreamVideoFormat(const BitmapInfoHeader& f);
void writeStreamVideoFormatChunk(const unsigned char* pData, size_t sizeData);
void writeStreamVideoFormat(const unsigned char* pData, size_t sizeData);
void writeStreamAudioFormatChunk(const WaveFormatEx&);
void writeStreamAudioFormat(const WaveFormatEx&);
int headerLength() const;
int streamHeaderLength(int stream) const;
void load(const SuperIndexChunk::Entry&, FrameIndex&) const;
class handle_t
{
public:
handle_t();
void open(const char*, mode_t, dword) throw (FileError);
void close();
bool isOpen() const;
offset_t size() const;
void read(void*, size_t) const;
void write(const void*, size_t) const;
void truncate() const;
void seekCurrent(offset_t) const;
void seek(offset_t) const;
offset_t tell() const;
void mapinit();
void mapfinal();
unsigned long map(
offset_t offset,
length_t size,
unsigned char*& view,
length_t& viewSize,
length_t& offsetWithinView) const;
void unmap(unsigned char*, length_t) const;
private:
#if defined WIN32
HANDLE m_hFile;
HANDLE m_hFileMappingObject;
#elif defined LINUX
int m_fd;
#endif
};
handle_t m_handle;
mode_t m_mode;
std::string m_name;
OutputType m_ot;
MainHeader m_mainHeader;
ExtraHeaderVector m_extraHeaderVector;
class indx_t
{
public:
indx_t();
indx_t(int entryCount);
~indx_t();
int entryCount() const;
size_t size() const;
operator SuperIndexChunk&() const;
void read(File&);
void write(File&) const;
private:
indx_t(const indx_t&);
indx_t& operator=(const indx_t&);
dword* m_rep;
};
struct StreamInfo
{
virtual ~StreamInfo();
void write(File&) const;
int length() const;
StreamHeader header;
typedef std::vector<unsigned char> data_t;
data_t m_data;
std::string m_name;
ExtraHeaderVector m_extraHeaderVector;
indx_t m_indx;
protected:
StreamInfo(int);
StreamInfo(const StreamHeader&);
virtual int strf_length() const = 0;
virtual void strf_write(File&) const = 0;
private:
StreamInfo(const StreamInfo&);
StreamInfo& operator=(const StreamInfo&);
};
struct StreamInfoVideo : public StreamInfo
{
StreamInfoVideo(int entryCount);
StreamInfoVideo(const StreamHeader&);
~StreamInfoVideo();
// BitmapInfoHeader m_strf;
unsigned char* m_strf;
size_t m_strfSize;
protected:
int strf_length() const;
void strf_write(File&) const;
};
struct StreamInfoAudio : public StreamInfo
{
StreamInfoAudio(int entryCount);
StreamInfoAudio(const StreamHeader&);
WaveFormatEx m_strf;
protected:
int strf_length() const;
void strf_write(File&) const;
};
friend struct StreamInfo;
friend struct StreamInfoVideo;
friend struct StreamInfoAudio;
void readStreamData(StreamInfo::data_t&);
typedef std::vector<StreamInfo*> infoVector_t;
infoVector_t infoVector;
dword m_totalFrames;
offset_t m_dataPosn;
offset_t m_indexPosn;
int m_indexCount;
length_t m_idx1Size;
struct SegmentInfo
{
offset_t offset;
size_t size;
SegmentInfo() {}
SegmentInfo(offset_t offset_) : offset(offset_) {}
};
typedef std::vector<SegmentInfo> SegmentInfoVector;
SegmentInfoVector m_segmentInfo;
};
#if defined WIN32
class MappedFile
{
public:
enum { invalid_offset = -1 };
MappedFile();
MappedFile(const char* name);
~MappedFile();
void open(const char* name);
void close();
bool isOpen() const;
const char* name() const;
const MainHeader& mainHeader() const;
const StreamHeader& streamHeader(int stream) const;
const BitmapInfoHeader& videoFormat(int stream) const;
const WaveFormatEx& audioFormat(int stream) const;
const char* streamName(int stream) const;
dword totalFrames() const;
offset_t dataOffset() const;
offset_t indexOffset() const;
size_t indexSize() const;
offset_t indexChunkExOffset(int stream) const;
size_t indexChunkExSize(int stream) const;
const void* map(offset_t, size_t) const;
void unmap(const void*) const;
void load(int stream, FrameIEVector& index) const;
private:
MappedFile(const MappedFile&);
MappedFile& operator=(const MappedFile&);
void init();
void unmapAllViews();
offset_t offset() const;
void setFilePointerCurrent(LONG) const;
const FourCC readFourCC() const;
const FourCC queryFourCC() const;
dword readLength() const;
void readHeaderList();
void readDataList();
void readIndexList();
void readJunkChunk() const;
void readUnknownChunk() const;
void readMainHeaderChunk();
void readStreamHeaderList(int stream);
void readStreamHeaderChunk(StreamHeader&) const;
void readStreamVideoFormatChunk(BitmapInfoHeader&) const;
void readStreamAudioFormatChunk(WaveFormatEx&) const;
void readStreamNameChunk(std::string&) const;
void readIndexChunkEx(offset_t&, size_t&) const;
void readExtendedAVIHeaderList() const;
std::string m_name;
HANDLE m_file;
HANDLE m_fileMappingObject;
DWORD m_allocationGranularity;
MainHeader m_mainHeader;
struct StreamInfo
{
StreamHeader streamHeader;
union
{
BitmapInfoHeader* videoFormat;
WaveFormatEx* audioFormat;
};
std::string name;
offset_t indexChunkExOffset;
size_t indexChunkExSize;
};
typedef std::vector<StreamInfo> StreamInfoVector;
StreamInfoVector m_streamInfoVector;
size_t readChunkSize(offset_t) const;
int countEntries(int, const IndexEntry*, int) const;
int countEntries(const SuperIndexChunk&) const;
void loadIndex(int, FrameIEVector&) const;
void loadIndexEx(int, FrameIEVector&) const;
void load(const SuperIndexChunk::Entry&, FrameIEVector&) const;
mutable dword m_totalFrames;
offset_t m_dataOffset;
offset_t m_indexOffset;
size_t m_indexSize;
struct ViewInfo
{
unsigned char* pView;
unsigned char* pChunk;
};
typedef std::list<ViewInfo> Views;
mutable Views m_views;
Views::iterator findView(const void*) const;
};
#endif
}
//inline HANDLE AVI::File::handle() const
//{
// return m_handle;
//}
inline AVI::Chunk::Chunk(
const FourCC fcc,
length_t length,
const unsigned char* d)
: m_fcc(fcc)
{
// if (m_length > 0)
// {
// m_data = new unsigned char[m_length];
// if (m_data == 0)
// {
// throw FileError("Error allocating Chunk data.");
// }
// if (data != 0)
// {
// memcpy(m_data, data, m_length);
// }
// }
if (length)
{
if (d)
{
//typedef data_t::const_iterator iter_t;
//const iter_t first = iter_t(d);
//const data_t::size_type n = length;
//const iter_t last = first + n;
m_data.assign(d, d + length);
}
else
{
const data_t::size_type n = length;
m_data.assign(n, 0);
}
}
else
{
m_data.assign(data_t::size_type(0), 0);
}
}
inline const FourCC AVI::Chunk::fcc() const
{
return m_fcc;
}
inline AVI::length_t AVI::Chunk::length() const
{
const data_t::size_type n = m_data.size();
return n;
}
inline const unsigned char* AVI::Chunk::data() const
{
return &m_data[0];
}
inline unsigned char* AVI::Chunk::data()
{
return &m_data[0];
}
inline void AVI::Chunk::data(const unsigned char* d)
{
//typedef data_t::const_iterator iter_t;
//const iter_t first = iter_t(d);
//const data_t::size_type n = m_data.size();
//const iter_t last = first + n;
m_data.assign(d, d + m_data.size());
}
inline AVI::dword AVI::FileError::id() const
{
return m_id;
}
#endif