Split AVI file structure related classes to dedicated file
This commit is contained in:
parent
f292f7babe
commit
29d94212a8
3 changed files with 439 additions and 366 deletions
261
avi/avi_structure.cpp
Normal file
261
avi/avi_structure.cpp
Normal file
|
@ -0,0 +1,261 @@
|
|||
#include "avi_structure.hpp"
|
||||
#include "library/serialization.hpp"
|
||||
#include <cstring>
|
||||
|
||||
stream_format_base::~stream_format_base() {}
|
||||
stream_format_video::~stream_format_video() {}
|
||||
stream_format_audio::~stream_format_audio() {}
|
||||
|
||||
|
||||
uint32_t stream_format_video::type() { return 0x73646976; }
|
||||
uint32_t stream_format_video::scale() { return fps_d; }
|
||||
uint32_t stream_format_video::rate() { return fps_n; }
|
||||
uint32_t stream_format_video::rect_left() { return 0; }
|
||||
uint32_t stream_format_video::rect_top() { return 0; }
|
||||
uint32_t stream_format_video::rect_right() { return width; }
|
||||
uint32_t stream_format_video::rect_bottom() { return height; }
|
||||
uint32_t stream_format_video::sample_size() { return (bit_count + 7) / 8; }
|
||||
size_t stream_format_video::size() { return 48 + extra.size(); }
|
||||
void stream_format_video::serialize(std::ostream& out)
|
||||
{
|
||||
std::vector<char> buf;
|
||||
buf.resize(size());
|
||||
write32ule(&buf[0], 0x66727473UL); //Type
|
||||
write32ule(&buf[4], size() - 8); //Size.
|
||||
write32ule(&buf[8], 40 + extra.size()); //BITMAPINFOHEADER size.
|
||||
write32ule(&buf[12], width);
|
||||
write32ule(&buf[16], height);
|
||||
write16ule(&buf[20], planes);
|
||||
write16ule(&buf[22], bit_count);
|
||||
write32ule(&buf[24], compression);
|
||||
write32ule(&buf[28], size_image);
|
||||
write32ule(&buf[32], resolution_x);
|
||||
write32ule(&buf[36], resolution_y);
|
||||
write32ule(&buf[40], clr_used);
|
||||
write32ule(&buf[44], clr_important);
|
||||
memcpy(&buf[48], &extra[0], extra.size());
|
||||
out.write(&buf[0], buf.size());
|
||||
if(!out)
|
||||
throw std::runtime_error("Can't write strf (video)");
|
||||
}
|
||||
|
||||
uint32_t stream_format_audio::type() { return 0x73647561; }
|
||||
uint32_t stream_format_audio::scale() { return 1; }
|
||||
uint32_t stream_format_audio::rate() { return samples_per_second; }
|
||||
uint32_t stream_format_audio::rect_left() { return 0; }
|
||||
uint32_t stream_format_audio::rect_top() { return 0; }
|
||||
uint32_t stream_format_audio::rect_right() { return 0; }
|
||||
uint32_t stream_format_audio::rect_bottom() { return 0; }
|
||||
uint32_t stream_format_audio::sample_size() { return blocksize; }
|
||||
size_t stream_format_audio::size() { return (29 + extra.size()) / 4 * 4; }
|
||||
|
||||
void stream_format_audio::serialize(std::ostream& out)
|
||||
{
|
||||
std::vector<char> buf;
|
||||
buf.resize(size());
|
||||
write32ule(&buf[0], 0x66727473UL); //Type
|
||||
write32ule(&buf[4], size() - 8); //Size.
|
||||
write16ule(&buf[8], format_tag);
|
||||
write16ule(&buf[10], channels);
|
||||
write32ule(&buf[12], samples_per_second);
|
||||
write32ule(&buf[16], average_bytes_per_second);
|
||||
write16ule(&buf[20], block_align);
|
||||
write16ule(&buf[22], bits_per_sample);
|
||||
write16ule(&buf[24], extra.size()); //Extension data.
|
||||
memset(&buf[26], 0, size() - 26); //Pad
|
||||
memcpy(&buf[26], &extra[0], extra.size());
|
||||
out.write(&buf[0], buf.size());
|
||||
if(!out)
|
||||
throw std::runtime_error("Can't write strf (audio)");
|
||||
}
|
||||
|
||||
size_t stream_header::size() { return 72; }
|
||||
stream_header::stream_header() { length = 0; }
|
||||
void stream_header::add_frames(size_t count) { length = length + count; }
|
||||
|
||||
void stream_header::serialize(std::ostream& out, struct stream_format_base& format)
|
||||
{
|
||||
std::vector<char> buf;
|
||||
buf.resize(size());
|
||||
write32ule(&buf[0], 0x68727473UL); //Type
|
||||
write32ule(&buf[4], size() - 8); //Size.
|
||||
write32ule(&buf[8], format.type());
|
||||
write32ule(&buf[12], handler);
|
||||
write32ule(&buf[16], flags);
|
||||
write16ule(&buf[20], priority);
|
||||
write16ule(&buf[22], language);
|
||||
write32ule(&buf[24], initial_frames);
|
||||
write32ule(&buf[28], format.scale());
|
||||
write32ule(&buf[32], format.rate());
|
||||
write32ule(&buf[36], start);
|
||||
write32ule(&buf[40], length);
|
||||
write32ule(&buf[44], suggested_buffer_size);
|
||||
write32ule(&buf[48], quality);
|
||||
write32ule(&buf[52], format.sample_size());
|
||||
write32ule(&buf[56], format.rect_left());
|
||||
write32ule(&buf[60], format.rect_top());
|
||||
write32ule(&buf[64], format.rect_right());
|
||||
write32ule(&buf[68], format.rect_bottom());
|
||||
out.write(&buf[0], buf.size());
|
||||
if(!out)
|
||||
throw std::runtime_error("Can't write strh");
|
||||
}
|
||||
|
||||
template<class format>
|
||||
size_t stream_header_list<format>::size() { return 12 + strh.size() + strf.size(); }
|
||||
|
||||
template<class format>
|
||||
void stream_header_list<format>::serialize(std::ostream& out)
|
||||
{
|
||||
std::vector<char> buf;
|
||||
buf.resize(12);
|
||||
write32ule(&buf[0], 0x5453494CUL); //List.
|
||||
write32ule(&buf[4], size() - 8);
|
||||
write32ule(&buf[8], 0x6c727473UL); //Type.
|
||||
out.write(&buf[0], buf.size());
|
||||
if(!out)
|
||||
throw std::runtime_error("Can't write strl");
|
||||
strh.serialize(out, strf);
|
||||
strf.serialize(out);
|
||||
}
|
||||
|
||||
size_t avi_header::size() { return 64; }
|
||||
void avi_header::serialize(std::ostream& out, stream_header_list<stream_format_video>& videotrack, uint32_t tracks)
|
||||
{
|
||||
std::vector<char> buf;
|
||||
buf.resize(size());
|
||||
write32ule(&buf[0], 0x68697661); //Type.
|
||||
write32ule(&buf[4], size() - 8);
|
||||
write32ule(&buf[8], microsec_per_frame);
|
||||
write32ule(&buf[12], max_bytes_per_sec);
|
||||
write32ule(&buf[16], padding_granularity);
|
||||
write32ule(&buf[20], flags);
|
||||
write32ule(&buf[24], videotrack.strh.length);
|
||||
write32ule(&buf[28], initial_frames);
|
||||
write32ule(&buf[32], tracks);
|
||||
write32ule(&buf[36], suggested_buffer_size);
|
||||
write32ule(&buf[40], videotrack.strf.width);
|
||||
write32ule(&buf[44], videotrack.strf.height);
|
||||
write32ule(&buf[48], 0);
|
||||
write32ule(&buf[52], 0);
|
||||
write32ule(&buf[56], 0);
|
||||
write32ule(&buf[60], 0);
|
||||
out.write(&buf[0], buf.size());
|
||||
if(!out)
|
||||
throw std::runtime_error("Can't write avih");
|
||||
}
|
||||
|
||||
size_t header_list::size() { return 12 + avih.size() + videotrack.size() + audiotrack.size(); }
|
||||
void header_list::serialize(std::ostream& out)
|
||||
{
|
||||
std::vector<char> buf;
|
||||
buf.resize(12);
|
||||
write32ule(&buf[0], 0x5453494CUL); //List.
|
||||
write32ule(&buf[4], size() - 8);
|
||||
write32ule(&buf[8], 0x6c726468UL); //Type.
|
||||
out.write(&buf[0], buf.size());
|
||||
if(!out)
|
||||
throw std::runtime_error("Can't write hdrl");
|
||||
avih.serialize(out, videotrack, 2);
|
||||
videotrack.serialize(out);
|
||||
audiotrack.serialize(out);
|
||||
}
|
||||
|
||||
size_t movi_chunk::write_offset() { return 12; }
|
||||
size_t movi_chunk::size() { return 12 + payload_size; }
|
||||
movi_chunk::movi_chunk() { payload_size = 0; }
|
||||
void movi_chunk::add_payload(size_t s) { payload_size = payload_size + s; }
|
||||
void movi_chunk::serialize(std::ostream& out)
|
||||
{
|
||||
std::vector<char> buf;
|
||||
buf.resize(12);
|
||||
write32ule(&buf[0], 0x5453494CUL); //List.
|
||||
write32ule(&buf[4], size() - 8);
|
||||
write32ule(&buf[8], 0x69766f6d); //Type.
|
||||
out.write(&buf[0], buf.size());
|
||||
out.seekp(payload_size, std::ios_base::cur);
|
||||
if(!out)
|
||||
throw std::runtime_error("Can't write movi");
|
||||
}
|
||||
|
||||
size_t index_entry::size() { return 16; }
|
||||
index_entry::index_entry(uint32_t _chunk_type, uint32_t _flags, uint32_t _offset, uint32_t _length)
|
||||
{
|
||||
chunk_type = _chunk_type;
|
||||
flags = _flags;
|
||||
offset = _offset;
|
||||
length = _length;
|
||||
}
|
||||
|
||||
void index_entry::serialize(std::ostream& out)
|
||||
{
|
||||
std::vector<char> buf;
|
||||
buf.resize(16);
|
||||
write32ule(&buf[0], chunk_type);
|
||||
write32ule(&buf[4], flags);
|
||||
write32ule(&buf[8], offset);
|
||||
write32ule(&buf[12], length);
|
||||
out.write(&buf[0], buf.size());
|
||||
if(!out)
|
||||
throw std::runtime_error("Can't write index entry");
|
||||
}
|
||||
|
||||
void idx1_chunk::add_entry(const index_entry& entry) { entries.push_back(entry); }
|
||||
size_t idx1_chunk::size()
|
||||
{
|
||||
size_t s = 8;
|
||||
//Not exactly right, but much faster than the proper way.
|
||||
if(entries.empty())
|
||||
return s;
|
||||
s = s + entries.begin()->size() * entries.size();
|
||||
return s;
|
||||
}
|
||||
|
||||
void idx1_chunk::serialize(std::ostream& out)
|
||||
{
|
||||
std::vector<char> buf;
|
||||
buf.resize(8);
|
||||
write32ule(&buf[0], 0x31786469UL); //Type.
|
||||
write32ule(&buf[4], size() - 8);
|
||||
out.write(&buf[0], buf.size());
|
||||
if(!out)
|
||||
throw std::runtime_error("Can't write idx1");
|
||||
for(std::list<index_entry>::iterator i = entries.begin(); i != entries.end(); i++)
|
||||
i->serialize(out);
|
||||
}
|
||||
|
||||
size_t avi_file_structure::write_offset() { return 12 + hdrl.size() + movi.write_offset(); }
|
||||
size_t avi_file_structure::size() { return 12 + hdrl.size() + movi.size() + idx1.size(); }
|
||||
void avi_file_structure::serialize(std::ostream& out)
|
||||
{
|
||||
std::vector<char> buf;
|
||||
buf.resize(12);
|
||||
write32ule(&buf[0], 0x46464952UL); //RIFF.
|
||||
write32ule(&buf[4], size() - 8);
|
||||
write32ule(&buf[8], 0x20495641UL); //Type.
|
||||
out.write(&buf[0], buf.size());
|
||||
if(!out)
|
||||
throw std::runtime_error("Can't write AVI header");
|
||||
hdrl.serialize(out);
|
||||
movi.serialize(out);
|
||||
idx1.serialize(out);
|
||||
}
|
||||
|
||||
void avi_file_structure::start_data(std::ostream& out)
|
||||
{
|
||||
out.seekp(0, std::ios_base::beg);
|
||||
size_t reserved_for_header = write_offset();
|
||||
std::vector<char> tmp;
|
||||
tmp.resize(reserved_for_header);
|
||||
out.write(&tmp[0], tmp.size());
|
||||
if(!out)
|
||||
throw std::runtime_error("Can't write dummy header");
|
||||
}
|
||||
|
||||
void avi_file_structure::finish_avi(std::ostream& out)
|
||||
{
|
||||
out.seekp(0, std::ios_base::beg);
|
||||
serialize(out);
|
||||
if(!out)
|
||||
throw std::runtime_error("Can't finish AVI");
|
||||
}
|
177
avi/avi_structure.hpp
Normal file
177
avi/avi_structure.hpp
Normal file
|
@ -0,0 +1,177 @@
|
|||
#ifndef _avi__avi_structure__hpp__included__
|
||||
#define _avi__avi_structure__hpp__included__
|
||||
|
||||
#include <cstdint>
|
||||
#include <cstdlib>
|
||||
#include <iostream>
|
||||
#include <stdexcept>
|
||||
#include <vector>
|
||||
#include <list>
|
||||
|
||||
|
||||
struct stream_format_base
|
||||
{
|
||||
virtual ~stream_format_base();
|
||||
/**
|
||||
* Type of track.
|
||||
* - 0x73646976 for video tracks.
|
||||
* - 0x73647561 for audio tracks.
|
||||
*/
|
||||
virtual uint32_t type() = 0;
|
||||
/**
|
||||
* Denomerator of samping/frame rate.
|
||||
*/
|
||||
virtual uint32_t scale() = 0;
|
||||
/**
|
||||
* Numerator of samping/frame rate.
|
||||
*/
|
||||
virtual uint32_t rate() = 0;
|
||||
virtual uint32_t sample_size() = 0;
|
||||
virtual uint32_t rect_left() = 0;
|
||||
virtual uint32_t rect_top() = 0;
|
||||
virtual uint32_t rect_right() = 0;
|
||||
virtual uint32_t rect_bottom() = 0;
|
||||
virtual size_t size() = 0;
|
||||
virtual void serialize(std::ostream& out) = 0;
|
||||
};
|
||||
|
||||
struct stream_format_video : public stream_format_base
|
||||
{
|
||||
~stream_format_video();
|
||||
uint32_t type();
|
||||
uint32_t scale();
|
||||
uint32_t rate();
|
||||
uint32_t rect_left();
|
||||
uint32_t rect_top();
|
||||
uint32_t rect_right();
|
||||
uint32_t rect_bottom();
|
||||
uint32_t sample_size();
|
||||
size_t size();
|
||||
uint32_t width;
|
||||
uint32_t height;
|
||||
uint16_t planes;
|
||||
uint16_t bit_count;
|
||||
uint32_t compression;
|
||||
uint32_t size_image;
|
||||
uint32_t resolution_x;
|
||||
uint32_t resolution_y;
|
||||
uint32_t clr_used;
|
||||
uint32_t clr_important;
|
||||
uint32_t fps_n;
|
||||
uint32_t fps_d;
|
||||
std::vector<char> extra;
|
||||
void serialize(std::ostream& out);
|
||||
};
|
||||
|
||||
struct stream_format_audio : public stream_format_base
|
||||
{
|
||||
~stream_format_audio();
|
||||
uint32_t type();
|
||||
uint32_t scale();
|
||||
uint32_t rate();
|
||||
uint32_t rect_left();
|
||||
uint32_t rect_top();
|
||||
uint32_t rect_right();
|
||||
uint32_t rect_bottom();
|
||||
uint32_t sample_size();
|
||||
size_t size();
|
||||
uint16_t format_tag;
|
||||
uint16_t channels;
|
||||
uint32_t samples_per_second;
|
||||
uint32_t average_bytes_per_second;
|
||||
uint16_t block_align;
|
||||
uint16_t bits_per_sample;
|
||||
uint32_t blocksize;
|
||||
std::vector<char> extra;
|
||||
void serialize(std::ostream& out);
|
||||
};
|
||||
|
||||
struct stream_header
|
||||
{
|
||||
size_t size();
|
||||
uint32_t handler;
|
||||
uint32_t flags;
|
||||
uint16_t priority;
|
||||
uint16_t language;
|
||||
uint32_t initial_frames;
|
||||
uint32_t start;
|
||||
uint32_t length;
|
||||
uint32_t suggested_buffer_size;
|
||||
uint32_t quality;
|
||||
stream_header();
|
||||
void add_frames(size_t count);
|
||||
void serialize(std::ostream& out, struct stream_format_base& format);
|
||||
};
|
||||
|
||||
template<class format>
|
||||
struct stream_header_list
|
||||
{
|
||||
size_t size();
|
||||
stream_header strh;
|
||||
format strf;
|
||||
void serialize(std::ostream& out);
|
||||
};
|
||||
|
||||
struct avi_header
|
||||
{
|
||||
size_t size();
|
||||
uint32_t microsec_per_frame;
|
||||
uint32_t max_bytes_per_sec;
|
||||
uint32_t padding_granularity;
|
||||
uint32_t flags;
|
||||
uint32_t initial_frames;
|
||||
uint32_t suggested_buffer_size;
|
||||
void serialize(std::ostream& out, stream_header_list<stream_format_video>& videotrack, uint32_t tracks);
|
||||
};
|
||||
|
||||
struct header_list
|
||||
{
|
||||
size_t size();
|
||||
avi_header avih;
|
||||
stream_header_list<stream_format_video> videotrack;
|
||||
stream_header_list<stream_format_audio> audiotrack;
|
||||
void serialize(std::ostream& out);
|
||||
};
|
||||
|
||||
struct movi_chunk
|
||||
{
|
||||
uint32_t payload_size;
|
||||
size_t write_offset();
|
||||
size_t size();
|
||||
movi_chunk();
|
||||
void add_payload(size_t s);
|
||||
void serialize(std::ostream& out);
|
||||
};
|
||||
|
||||
struct index_entry
|
||||
{
|
||||
size_t size();
|
||||
uint32_t chunk_type;
|
||||
uint32_t flags;
|
||||
uint32_t offset;
|
||||
uint32_t length;
|
||||
index_entry(uint32_t _chunk_type, uint32_t _flags, uint32_t _offset, uint32_t _length);
|
||||
void serialize(std::ostream& out);
|
||||
};
|
||||
|
||||
struct idx1_chunk
|
||||
{
|
||||
void add_entry(const index_entry& entry);
|
||||
std::list<index_entry> entries;
|
||||
size_t size();
|
||||
void serialize(std::ostream& out);
|
||||
};
|
||||
|
||||
struct avi_file_structure
|
||||
{
|
||||
size_t write_offset();
|
||||
size_t size();
|
||||
header_list hdrl;
|
||||
movi_chunk movi;
|
||||
idx1_chunk idx1;
|
||||
void serialize(std::ostream& out);
|
||||
void start_data(std::ostream& out);
|
||||
void finish_avi(std::ostream& out);
|
||||
};
|
||||
|
||||
#endif
|
367
avi/cscd.cpp
367
avi/cscd.cpp
|
@ -7,6 +7,7 @@
|
|||
#include <vector>
|
||||
#include <iostream>
|
||||
#include <list>
|
||||
#include "avi_structure.hpp"
|
||||
#include "library/serialization.hpp"
|
||||
|
||||
#define AVI_CUTOFF_SIZE 2100000000
|
||||
|
@ -27,330 +28,6 @@ namespace
|
|||
}
|
||||
};
|
||||
|
||||
struct stream_format_base
|
||||
{
|
||||
virtual ~stream_format_base();
|
||||
virtual unsigned long type() = 0;
|
||||
virtual unsigned long scale() = 0;
|
||||
virtual unsigned long rate() = 0;
|
||||
virtual unsigned long sample_size() = 0;
|
||||
virtual unsigned long rect_left() = 0;
|
||||
virtual unsigned long rect_top() = 0;
|
||||
virtual unsigned long rect_right() = 0;
|
||||
virtual unsigned long rect_bottom() = 0;
|
||||
virtual size_t size() = 0;
|
||||
virtual void serialize(std::ostream& out) = 0;
|
||||
};
|
||||
|
||||
struct stream_format_video : public stream_format_base
|
||||
{
|
||||
~stream_format_video();
|
||||
unsigned long type() { return 0x73646976UL; }
|
||||
unsigned long scale() { return fps_d; }
|
||||
unsigned long rate() { return fps_n; }
|
||||
unsigned long rect_left() { return 0; }
|
||||
unsigned long rect_top() { return 0; }
|
||||
unsigned long rect_right() { return width; }
|
||||
unsigned long rect_bottom() { return height; }
|
||||
unsigned long sample_size() { return (bit_count + 7) / 8; }
|
||||
size_t size() { return 48; }
|
||||
unsigned long width;
|
||||
unsigned long height;
|
||||
unsigned planes;
|
||||
unsigned bit_count;
|
||||
unsigned long compression;
|
||||
unsigned long size_image;
|
||||
unsigned long resolution_x;
|
||||
unsigned long resolution_y;
|
||||
unsigned long clr_used;
|
||||
unsigned long clr_important;
|
||||
unsigned long fps_n;
|
||||
unsigned long fps_d;
|
||||
void serialize(std::ostream& out)
|
||||
{
|
||||
std::vector<char> buf;
|
||||
buf.resize(size());
|
||||
write32ule(&buf[0], 0x66727473UL); //Type
|
||||
write32ule(&buf[4], size() - 8); //Size.
|
||||
write32ule(&buf[8], 40); //BITMAPINFOHEADER size.
|
||||
write32ule(&buf[12], width);
|
||||
write32ule(&buf[16], height);
|
||||
write16ule(&buf[20], planes);
|
||||
write16ule(&buf[22], bit_count);
|
||||
write32ule(&buf[24], compression);
|
||||
write32ule(&buf[28], size_image);
|
||||
write32ule(&buf[32], resolution_x);
|
||||
write32ule(&buf[36], resolution_y);
|
||||
write32ule(&buf[40], clr_used);
|
||||
write32ule(&buf[44], clr_important);
|
||||
out.write(&buf[0], buf.size());
|
||||
if(!out)
|
||||
throw std::runtime_error("Can't write strf (video)");
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
struct stream_format_audio : public stream_format_base
|
||||
{
|
||||
~stream_format_audio();
|
||||
unsigned long type() { return 0x73647561; }
|
||||
unsigned long scale() { return 1; }
|
||||
unsigned long rate() { return samples_per_second; }
|
||||
unsigned long rect_left() { return 0; }
|
||||
unsigned long rect_top() { return 0; }
|
||||
unsigned long rect_right() { return 0; }
|
||||
unsigned long rect_bottom() { return 0; }
|
||||
unsigned long sample_size() { return blocksize; }
|
||||
size_t size() { return 28; }
|
||||
unsigned format_tag;
|
||||
unsigned channels;
|
||||
unsigned long samples_per_second;
|
||||
unsigned long average_bytes_per_second;
|
||||
unsigned block_align;
|
||||
unsigned bits_per_sample;
|
||||
unsigned long blocksize;
|
||||
void serialize(std::ostream& out)
|
||||
{
|
||||
std::vector<char> buf;
|
||||
buf.resize(size());
|
||||
write32ule(&buf[0], 0x66727473UL); //Type
|
||||
write32ule(&buf[4], size() - 8); //Size.
|
||||
write16ule(&buf[8], format_tag);
|
||||
write16ule(&buf[10], channels);
|
||||
write32ule(&buf[12], samples_per_second);
|
||||
write32ule(&buf[16], average_bytes_per_second);
|
||||
write16ule(&buf[20], block_align);
|
||||
write16ule(&buf[22], bits_per_sample);
|
||||
write16ule(&buf[24], 0); //No extension data.
|
||||
write16ule(&buf[26], 0); //Pad
|
||||
out.write(&buf[0], buf.size());
|
||||
if(!out)
|
||||
throw std::runtime_error("Can't write strf (audio)");
|
||||
}
|
||||
};
|
||||
|
||||
stream_format_base::~stream_format_base() {}
|
||||
stream_format_video::~stream_format_video() {}
|
||||
stream_format_audio::~stream_format_audio() {}
|
||||
|
||||
struct stream_header
|
||||
{
|
||||
size_t size() { return 72; }
|
||||
unsigned long handler;
|
||||
unsigned long flags;
|
||||
unsigned priority;
|
||||
unsigned language;
|
||||
unsigned long initial_frames;
|
||||
unsigned long start;
|
||||
unsigned long length;
|
||||
unsigned long suggested_buffer_size;
|
||||
unsigned long quality;
|
||||
stream_header()
|
||||
{
|
||||
length = 0;
|
||||
}
|
||||
|
||||
void add_frames(size_t count)
|
||||
{
|
||||
length = length + count;
|
||||
}
|
||||
|
||||
void serialize(std::ostream& out, struct stream_format_base& format)
|
||||
{
|
||||
std::vector<char> buf;
|
||||
buf.resize(size());
|
||||
write32ule(&buf[0], 0x68727473UL); //Type
|
||||
write32ule(&buf[4], size() - 8); //Size.
|
||||
write32ule(&buf[8], format.type());
|
||||
write32ule(&buf[12], handler);
|
||||
write32ule(&buf[16], flags);
|
||||
write16ule(&buf[20], priority);
|
||||
write16ule(&buf[22], language);
|
||||
write32ule(&buf[24], initial_frames);
|
||||
write32ule(&buf[28], format.scale());
|
||||
write32ule(&buf[32], format.rate());
|
||||
write32ule(&buf[36], start);
|
||||
write32ule(&buf[40], length);
|
||||
write32ule(&buf[44], suggested_buffer_size);
|
||||
write32ule(&buf[48], quality);
|
||||
write32ule(&buf[52], format.sample_size());
|
||||
write32ule(&buf[56], format.rect_left());
|
||||
write32ule(&buf[60], format.rect_top());
|
||||
write32ule(&buf[64], format.rect_right());
|
||||
write32ule(&buf[68], format.rect_bottom());
|
||||
out.write(&buf[0], buf.size());
|
||||
if(!out)
|
||||
throw std::runtime_error("Can't write strh");
|
||||
}
|
||||
};
|
||||
|
||||
template<class format>
|
||||
struct stream_header_list
|
||||
{
|
||||
size_t size() { return 12 + strh.size() + strf.size(); }
|
||||
stream_header strh;
|
||||
format strf;
|
||||
void serialize(std::ostream& out)
|
||||
{
|
||||
std::vector<char> buf;
|
||||
buf.resize(12);
|
||||
write32ule(&buf[0], 0x5453494CUL); //List.
|
||||
write32ule(&buf[4], size() - 8);
|
||||
write32ule(&buf[8], 0x6c727473UL); //Type.
|
||||
out.write(&buf[0], buf.size());
|
||||
if(!out)
|
||||
throw std::runtime_error("Can't write strl");
|
||||
strh.serialize(out, strf);
|
||||
strf.serialize(out);
|
||||
}
|
||||
};
|
||||
|
||||
struct avi_header
|
||||
{
|
||||
size_t size() { return 64; }
|
||||
unsigned long microsec_per_frame;
|
||||
unsigned long max_bytes_per_sec;
|
||||
unsigned long padding_granularity;
|
||||
unsigned long flags;
|
||||
unsigned long initial_frames;
|
||||
unsigned long suggested_buffer_size;
|
||||
void serialize(std::ostream& out, stream_header_list<stream_format_video>& videotrack,
|
||||
unsigned long tracks)
|
||||
{
|
||||
std::vector<char> buf;
|
||||
buf.resize(size());
|
||||
write32ule(&buf[0], 0x68697661); //Type.
|
||||
write32ule(&buf[4], size() - 8);
|
||||
write32ule(&buf[8], microsec_per_frame);
|
||||
write32ule(&buf[12], max_bytes_per_sec);
|
||||
write32ule(&buf[16], padding_granularity);
|
||||
write32ule(&buf[20], flags);
|
||||
write32ule(&buf[24], videotrack.strh.length);
|
||||
write32ule(&buf[28], initial_frames);
|
||||
write32ule(&buf[32], tracks);
|
||||
write32ule(&buf[36], suggested_buffer_size);
|
||||
write32ule(&buf[40], videotrack.strf.width);
|
||||
write32ule(&buf[44], videotrack.strf.height);
|
||||
write32ule(&buf[48], 0);
|
||||
write32ule(&buf[52], 0);
|
||||
write32ule(&buf[56], 0);
|
||||
write32ule(&buf[60], 0);
|
||||
out.write(&buf[0], buf.size());
|
||||
if(!out)
|
||||
throw std::runtime_error("Can't write avih");
|
||||
}
|
||||
};
|
||||
|
||||
struct header_list
|
||||
{
|
||||
size_t size() { return 12 + avih.size() + videotrack.size() + audiotrack.size(); }
|
||||
avi_header avih;
|
||||
stream_header_list<stream_format_video> videotrack;
|
||||
stream_header_list<stream_format_audio> audiotrack;
|
||||
void serialize(std::ostream& out)
|
||||
{
|
||||
std::vector<char> buf;
|
||||
buf.resize(12);
|
||||
write32ule(&buf[0], 0x5453494CUL); //List.
|
||||
write32ule(&buf[4], size() - 8);
|
||||
write32ule(&buf[8], 0x6c726468UL); //Type.
|
||||
out.write(&buf[0], buf.size());
|
||||
if(!out)
|
||||
throw std::runtime_error("Can't write hdrl");
|
||||
avih.serialize(out, videotrack, 2);
|
||||
videotrack.serialize(out);
|
||||
audiotrack.serialize(out);
|
||||
}
|
||||
};
|
||||
|
||||
struct movi_chunk
|
||||
{
|
||||
unsigned long payload_size;
|
||||
size_t write_offset() { return 12; }
|
||||
size_t size() { return 12 + payload_size; }
|
||||
|
||||
movi_chunk()
|
||||
{
|
||||
payload_size = 0;
|
||||
}
|
||||
|
||||
void add_payload(size_t s)
|
||||
{
|
||||
payload_size = payload_size + s;
|
||||
}
|
||||
|
||||
void serialize(std::ostream& out)
|
||||
{
|
||||
std::vector<char> buf;
|
||||
buf.resize(12);
|
||||
write32ule(&buf[0], 0x5453494CUL); //List.
|
||||
write32ule(&buf[4], size() - 8);
|
||||
write32ule(&buf[8], 0x69766f6d); //Type.
|
||||
out.write(&buf[0], buf.size());
|
||||
out.seekp(payload_size, std::ios_base::cur);
|
||||
if(!out)
|
||||
throw std::runtime_error("Can't write movi");
|
||||
}
|
||||
};
|
||||
|
||||
struct index_entry
|
||||
{
|
||||
size_t size() { return 16; }
|
||||
unsigned long chunk_type;
|
||||
unsigned long flags;
|
||||
unsigned long offset;
|
||||
unsigned long length;
|
||||
index_entry(unsigned long _chunk_type, unsigned long _flags, unsigned long _offset,
|
||||
unsigned long _length)
|
||||
{
|
||||
chunk_type = _chunk_type;
|
||||
flags = _flags;
|
||||
offset = _offset;
|
||||
length = _length;
|
||||
}
|
||||
|
||||
void serialize(std::ostream& out)
|
||||
{
|
||||
std::vector<char> buf;
|
||||
buf.resize(16);
|
||||
write32ule(&buf[0], chunk_type);
|
||||
write32ule(&buf[4], flags);
|
||||
write32ule(&buf[8], offset);
|
||||
write32ule(&buf[12], length);
|
||||
out.write(&buf[0], buf.size());
|
||||
if(!out)
|
||||
throw std::runtime_error("Can't write index entry");
|
||||
}
|
||||
};
|
||||
|
||||
struct idx1_chunk
|
||||
{
|
||||
void add_entry(const index_entry& entry) { entries.push_back(entry); }
|
||||
std::list<index_entry> entries;
|
||||
size_t size()
|
||||
{
|
||||
size_t s = 8;
|
||||
//Not exactly right, but much faster than the proper way.
|
||||
if(entries.empty())
|
||||
return s;
|
||||
s = s + entries.begin()->size() * entries.size();
|
||||
return s;
|
||||
}
|
||||
|
||||
void serialize(std::ostream& out)
|
||||
{
|
||||
std::vector<char> buf;
|
||||
buf.resize(8);
|
||||
write32ule(&buf[0], 0x31786469UL); //Type.
|
||||
write32ule(&buf[4], size() - 8);
|
||||
out.write(&buf[0], buf.size());
|
||||
if(!out)
|
||||
throw std::runtime_error("Can't write idx1");
|
||||
for(std::list<index_entry>::iterator i = entries.begin(); i != entries.end(); i++)
|
||||
i->serialize(out);
|
||||
}
|
||||
};
|
||||
|
||||
void copy_row(unsigned char* target, const unsigned char* src, unsigned width,
|
||||
enum avi_cscd_dumper::pixelformat pf)
|
||||
{
|
||||
|
@ -383,48 +60,6 @@ namespace
|
|||
}
|
||||
}
|
||||
|
||||
struct avi_file_structure
|
||||
{
|
||||
size_t write_offset() { return 12 + hdrl.size() + movi.write_offset(); }
|
||||
size_t size() { return 12 + hdrl.size() + movi.size() + idx1.size(); }
|
||||
header_list hdrl;
|
||||
movi_chunk movi;
|
||||
idx1_chunk idx1;
|
||||
void serialize(std::ostream& out)
|
||||
{
|
||||
std::vector<char> buf;
|
||||
buf.resize(12);
|
||||
write32ule(&buf[0], 0x46464952UL); //RIFF.
|
||||
write32ule(&buf[4], size() - 8);
|
||||
write32ule(&buf[8], 0x20495641UL); //Type.
|
||||
out.write(&buf[0], buf.size());
|
||||
if(!out)
|
||||
throw std::runtime_error("Can't write AVI header");
|
||||
hdrl.serialize(out);
|
||||
movi.serialize(out);
|
||||
idx1.serialize(out);
|
||||
}
|
||||
|
||||
void start_data(std::ostream& out)
|
||||
{
|
||||
out.seekp(0, std::ios_base::beg);
|
||||
size_t reserved_for_header = write_offset();
|
||||
std::vector<char> tmp;
|
||||
tmp.resize(reserved_for_header);
|
||||
out.write(&tmp[0], tmp.size());
|
||||
if(!out)
|
||||
throw std::runtime_error("Can't write dummy header");
|
||||
}
|
||||
|
||||
void finish_avi(std::ostream& out)
|
||||
{
|
||||
out.seekp(0, std::ios_base::beg);
|
||||
serialize(out);
|
||||
if(!out)
|
||||
throw std::runtime_error("Can't finish AVI");
|
||||
}
|
||||
};
|
||||
|
||||
namespace
|
||||
{
|
||||
void fill_avi_structure(struct avi_file_structure* avis, unsigned width, unsigned height, unsigned long fps_n,
|
||||
|
|
Loading…
Add table
Reference in a new issue