Merge branch 'rr1-maint'

This commit is contained in:
Ilari Liusvaara 2012-05-05 22:24:02 +03:00
commit 3df182b498
3 changed files with 71 additions and 53 deletions

View file

@ -42,6 +42,23 @@ struct zlibstream
* Parameter out: The buffer to write to. * Parameter out: The buffer to write to.
*/ */
void read(std::vector<char>& out); void read(std::vector<char>& out);
/**
* Read the data so far as buffer and empty compressed data.
*
* This performs a sync flush.
*
* Parameter out: The buffer to write to.
*/
void readsync(std::vector<char>& out);
/**
* Clear the output stream and add some uncompressed data.
*
* This is useful after doing readsync().
*
* Parameter data: The data to write (may be NULL if datalen=0).
* Parameter datalen: The length of data.
*/
void adddata(uint8_t* data, size_t datalen);
/** /**
* Set flag. * Set flag.
* *
@ -61,7 +78,9 @@ private:
size_t used; size_t used;
}; };
void flushpage(uint8_t* data, size_t datalen, bool final); void _read(std::vector<char>& out, int mode);
void _reset(uint8_t* data, size_t datalen, bool doactually);
void flushpage(uint8_t* data, size_t datalen, int mode);
zlibstream(zlibstream&); zlibstream(zlibstream&);
zlibstream& operator=(zlibstream&); zlibstream& operator=(zlibstream&);
z_stream z; z_stream z;

View file

@ -37,6 +37,11 @@ zlibstream::~zlibstream()
} }
void zlibstream::reset(uint8_t* data, size_t datalen) void zlibstream::reset(uint8_t* data, size_t datalen)
{
_reset(data, datalen, true);
}
void zlibstream::_reset(uint8_t* data, size_t datalen, bool doactually)
{ {
std::list<struct page> tmp; std::list<struct page> tmp;
size_t odatalen = datalen; size_t odatalen = datalen;
@ -48,7 +53,8 @@ void zlibstream::reset(uint8_t* data, size_t datalen)
data += copylen; data += copylen;
datalen -= copylen; datalen -= copylen;
} }
deflateReset(&z); if(doactually)
deflateReset(&z);
streamsize = odatalen; streamsize = odatalen;
flag = false; flag = false;
tmp.swap(storage); tmp.swap(storage);
@ -56,12 +62,17 @@ void zlibstream::reset(uint8_t* data, size_t datalen)
void zlibstream::write(uint8_t* data, size_t datalen) void zlibstream::write(uint8_t* data, size_t datalen)
{ {
flushpage(data, datalen, false); flushpage(data, datalen, 0);
} }
void zlibstream::read(std::vector<char>& out) void zlibstream::read(std::vector<char>& out)
{ {
flushpage(NULL, 0, true); _read(out, Z_FINISH);
}
void zlibstream::_read(std::vector<char>& out, int mode)
{
flushpage(NULL, 0, mode);
out.resize(streamsize); out.resize(streamsize);
size_t itr = 0; size_t itr = 0;
for(auto& i : storage) { for(auto& i : storage) {
@ -70,14 +81,11 @@ void zlibstream::read(std::vector<char>& out)
} }
} }
extern void* orig_return_address; void zlibstream::flushpage(uint8_t* data, size_t datalen, int mode)
extern void* orig_return_address2;
void zlibstream::flushpage(uint8_t* data, size_t datalen, bool final)
{ {
z.next_in = data; z.next_in = data;
z.avail_in = datalen; z.avail_in = datalen;
while(z.avail_in || final) { while(z.avail_in || mode) {
if(storage.empty() || storage.back().used == ZLIB_PAGE_STORAGE) { if(storage.empty() || storage.back().used == ZLIB_PAGE_STORAGE) {
storage.push_back(page()); storage.push_back(page());
storage.back().used = 0; storage.back().used = 0;
@ -85,15 +93,25 @@ void zlibstream::flushpage(uint8_t* data, size_t datalen, bool final)
z.next_out = storage.back().data + storage.back().used; z.next_out = storage.back().data + storage.back().used;
z.avail_out = ZLIB_PAGE_STORAGE - storage.back().used; z.avail_out = ZLIB_PAGE_STORAGE - storage.back().used;
size_t itmp = z.avail_out; size_t itmp = z.avail_out;
int x = deflate(&z, final ? Z_FINISH : 0); int x = deflate(&z, mode);
storage.back().used += (itmp - z.avail_out); storage.back().used += (itmp - z.avail_out);
streamsize += (itmp - z.avail_out); streamsize += (itmp - z.avail_out);
throw_zlib_error(x); throw_zlib_error(x);
if(final && x == Z_STREAM_END) if(mode && !z.avail_in && z.avail_out)
break; break;
} }
} }
void zlibstream::readsync(std::vector<char>& out)
{
_read(out, Z_SYNC_FLUSH);
}
void zlibstream::adddata(uint8_t* data, size_t datalen)
{
_reset(data, datalen, false);
}
void zlibstream::set_flag(bool f) void zlibstream::set_flag(bool f)
{ {
flag = f; flag = f;

View file

@ -1,5 +1,6 @@
#include "video/avi/codec.hpp" #include "video/avi/codec.hpp"
#include "core/settings.hpp" #include "core/settings.hpp"
#include "library/zlibstream.hpp"
#include <zlib.h> #include <zlib.h>
#include <limits> #include <limits>
#include <cstring> #include <cstring>
@ -51,8 +52,6 @@ namespace
unsigned pframes; unsigned pframes;
//Maximum number of P-frames to write in sequence. //Maximum number of P-frames to write in sequence.
unsigned max_pframes; unsigned max_pframes;
//Compression level to use.
unsigned level;
//Size of one block. //Size of one block.
uint32_t bw; uint32_t bw;
uint32_t bh; uint32_t bh;
@ -66,16 +65,12 @@ namespace
uint32_t* prev_frame; uint32_t* prev_frame;
//Scratch block pointer. //Scratch block pointer.
uint32_t* scratch; uint32_t* scratch;
//Output buffer. Sufficient space to hold both compressed and uncompressed data. //Output buffer. Sufficient space to hold uncompressed data.
std::vector<char> outbuffer; std::vector<char> outbuffer;
//Output scratch memory. //Output scratch memory.
char* oscratch; char* oscratch;
//The actual output buffer. Pointer, size and ued. //Zlib streaam.
char* outbuf; zlibstream z;
size_t outbuf_size;
size_t outbuf_used;
//Zlib state.
z_stream zstream;
//Compute penalty for motion vector (dx, dy) on block with upper-left corner at (bx, by). //Compute penalty for motion vector (dx, dy) on block with upper-left corner at (bx, by).
uint32_t mv_penalty(uint32_t bx, uint32_t by, int dx, int dy); uint32_t mv_penalty(uint32_t bx, uint32_t by, int dx, int dy);
//Do motion detection for block with upper-left corner at (bx, by). M is filled with the resulting //Do motion detection for block with upper-left corner at (bx, by). M is filled with the resulting
@ -125,6 +120,7 @@ namespace
void avi_codec_zmbv::serialize_frame(bool keyframe) void avi_codec_zmbv::serialize_frame(bool keyframe)
{ {
unsigned char tmp[7];
uint32_t nhb, nvb, nb; uint32_t nhb, nvb, nb;
//In_stride/in_offset is in units of words, out_stride is in units of bytes. //In_stride/in_offset is in units of words, out_stride is in units of bytes.
size_t in_stride = (ewidth + 2 * MAXIMUM_VECTOR); size_t in_stride = (ewidth + 2 * MAXIMUM_VECTOR);
@ -164,28 +160,21 @@ namespace
} }
compress: compress:
//Compress the output data. //Compress the output data.
zstream.next_in = reinterpret_cast<uint8_t*>(oscratch); if(keyframe)
zstream.avail_in = osize; {
tmp[0] = 1; //Keyframe
osize = 0; tmp[1] = 0; //Major version.
outbuf[osize++] = keyframe ? 1 : 0; //Indicate keyframe/not. tmp[2] = 1; //Minor version.
if(keyframe) { tmp[3] = 1; //Zlib compresison.
//Write the keyframe header. tmp[4] = 8; //32-bit
outbuf[osize++] = 0; //Version 0.1 tmp[5] = bw; //Block size.
outbuf[osize++] = 1; tmp[6] = bh; //Block size.
outbuf[osize++] = 1; //Zlib compression. z.reset(tmp, 7);
outbuf[osize++] = 8; //32 bit. } else {
outbuf[osize++] = bw; //Block size. tmp[0] = 0; //Not keyframe.
outbuf[osize++] = bh; z.adddata(tmp, 1);
deflateReset(&zstream); //Reset the zlib context.
} }
zstream.next_out = reinterpret_cast<uint8_t*>(&outbuf[osize]); z.write(reinterpret_cast<uint8_t*>(oscratch), osize);
zstream.avail_out = outbuf_size - osize;
if(deflate(&zstream, Z_SYNC_FLUSH) != Z_OK)
throw std::runtime_error("Zlib error while compressing data");
if(zstream.avail_in || !zstream.avail_out)
throw std::runtime_error("Buffer overrun while compressing data");
outbuf_used = outbuf_size - zstream.avail_out;
} }
//If candidate is better than best, update best. Returns true if ideal has been reached, else false. //If candidate is better than best, update best. Returns true if ideal has been reached, else false.
@ -228,7 +217,6 @@ compress:
avi_codec_zmbv::~avi_codec_zmbv() avi_codec_zmbv::~avi_codec_zmbv()
{ {
deflateEnd(&zstream);
} }
unsigned getzlevel(uint32_t _level) unsigned getzlevel(uint32_t _level)
@ -239,14 +227,11 @@ compress:
} }
avi_codec_zmbv::avi_codec_zmbv(uint32_t _level, uint32_t maxpframes, uint32_t _bw, uint32_t _bh) avi_codec_zmbv::avi_codec_zmbv(uint32_t _level, uint32_t maxpframes, uint32_t _bw, uint32_t _bh)
: z(getzlevel(_level))
{ {
bh = _bh; bh = _bh;
bw = _bw; bw = _bw;
level = _level;
max_pframes = maxpframes; max_pframes = maxpframes;
memset(&zstream, 0, sizeof(zstream));
if(deflateInit(&zstream, getzlevel(_level)))
throw std::runtime_error("Error initializing deflate");
} }
avi_video_codec::format avi_codec_zmbv::reset(uint32_t width, uint32_t height, uint32_t fps_n, uint32_t fps_d) avi_video_codec::format avi_codec_zmbv::reset(uint32_t width, uint32_t height, uint32_t fps_n, uint32_t fps_d)
@ -264,11 +249,8 @@ compress:
prev_frame = &pixbuf[(ewidth + 2 * MAXIMUM_VECTOR) * (eheight + 2 * MAXIMUM_VECTOR)]; prev_frame = &pixbuf[(ewidth + 2 * MAXIMUM_VECTOR) * (eheight + 2 * MAXIMUM_VECTOR)];
scratch = &pixbuf[2 * (ewidth + 2 * MAXIMUM_VECTOR) * (eheight + 2 * MAXIMUM_VECTOR)]; scratch = &pixbuf[2 * (ewidth + 2 * MAXIMUM_VECTOR) * (eheight + 2 * MAXIMUM_VECTOR)];
mv.resize(((ewidth + bw - 1) / bw) * ((eheight + bh - 1) / bh)); mv.resize(((ewidth + bw - 1) / bw) * ((eheight + bh - 1) / bh));
size_t maxdiff = 4 * ((mv.size() + 1) / 2) + 4 * ewidth * eheight; outbuffer.resize(4 * ((mv.size() + 1) / 2) + 4 * ewidth * eheight);
outbuf_size = deflateBound(&zstream, maxdiff) + 128; oscratch = &outbuffer[0];
outbuffer.resize(maxdiff + outbuf_size);
oscratch = &outbuffer[outbuf_size];
outbuf = &outbuffer[0];
memset(&pixbuf[0], 0, 4 * pixbuf.size()); memset(&pixbuf[0], 0, 4 * pixbuf.size());
return fmt; return fmt;
} }
@ -328,8 +310,7 @@ compress:
//Serialize and output. //Serialize and output.
serialize_frame(keyframe); serialize_frame(keyframe);
std::swap(current_frame, prev_frame); std::swap(current_frame, prev_frame);
out.payload.resize(outbuf_used); z.readsync(out.payload);
memcpy(&out.payload[0], outbuf, outbuf_used);
out.typecode = 0x6264; //Not exactly correct according to specs... out.typecode = 0x6264; //Not exactly correct according to specs...
out.hidden = false; out.hidden = false;
out.indexflags = keyframe ? 0x10 : 0; out.indexflags = keyframe ? 0x10 : 0;