[ create a new paste ] login | about

Link: http://codepad.org/ClluiIVM    [ raw code | fork ]

C++, pasted on Jun 7:
#include <vector>
#include <fstream>
#include <cassert>
#include "MVILoader.h"

struct Header
{
	int	major;
	int	minor;
	int	width;
	int	height;
	int	num_entries;
	int	num_audio;
	int	num_video;
	int	fps;
	int	has_audio;
	int	audio_num_channels;
	int	audio_samplerate;
	int	audio_bits;
};

struct VideoDiffHead
{
	int				num_payload1;
	int				num_colors;//muss nur ungleich 1 sein um änderungen anzuzeigen
	int				num_payload2;
	int				num_runlengths;//immer 9601
};

struct VideoDiffSubHeader
{
	int size_payload;
	int num_unzipped;
};

struct Decoder
{
	struct Entry
	{
		unsigned char	value;
		unsigned short	parent;
		unsigned short	count;

		Entry(unsigned char value=0, unsigned short parent=2, unsigned short count=1)
			: value(value), parent(parent), count(count)
		{}
	};

	const char*					in;
	size_t						in_offset;
	const unsigned char			EoiCode;
	unsigned short				CodeSize;
	std::vector<Entry>			dict;
	std::vector<unsigned char>&	out;

	Decoder(const char* in, std::vector<unsigned char> &out, size_t in_offset = 0)
		: in(in), in_offset(in_offset), out(out), EoiCode(2), CodeSize(9)
	{
		dict.reserve(1<<CodeSize);
		dict.insert(dict.begin(), 3, Entry());
		//fill the dict with 3 dummies and the rest
		for(unsigned short counter = 0; counter < 256; counter++)
			dict.push_back(Entry(static_cast<unsigned char>(counter)));
	}

	unsigned short GetNextCode(void)
	{
		//get the code from a big endian, bitwise read input
		unsigned int intCode;

		char tempbuf[] = { in[in_offset/8+3], in[in_offset/8+2], in[in_offset/8+1], in[in_offset/8+0] };

		memcpy((char*)&intCode, tempbuf, 4);

		unsigned int l = intCode >> (32 - CodeSize -(in_offset%8));//big endian -> little endian
		unsigned int Code = l & (0xFFFFFFFF >> (32 - CodeSize));//mask

		in_offset += CodeSize;					// Increase Bit Offset

		return static_cast<unsigned short>(Code);
	}

	unsigned char WriteOut(unsigned short in)
	{
		out.insert(out.end(),dict[in].count, 0);
		size_t offset = out.size();
		unsigned char last_written;

		while(in != EoiCode)
		{
			out[--offset]	= dict[in].value;
			last_written	= dict[in].value;
			in				= dict[in].parent;
		}
		return last_written;
	}

	void Decode(void)
	{
		unsigned short Code;
		unsigned short OldCode = GetNextCode();
			
		WriteOut(OldCode);

		while ((Code = GetNextCode()) != EoiCode)
		{
			if (Code == 0)//next mask
			{
				CodeSize++;
				dict.reserve(1<<CodeSize);
				if(in_offset%8) in_offset = (in_offset/8+1)*8;
			}
			else if(Code == 1)
			{
				assert(false);
			}
			else
			{
				unsigned char last_written = WriteOut(Code >= dict.size() ? OldCode : Code);
				
				if(Code >= dict.size())	out.push_back(last_written);

				dict.push_back(Entry(last_written, OldCode, dict[OldCode].count+1));
				OldCode = Code;
			}
		}
	}
};

void MVILoader::load(const char* _name)
{	
	Item item;
	Header header;

	std::string name_mvi(_name);
	name_mvi += ".MVI";

	file.open(name_mvi.c_str(), std::ios::out | std::ios::in | std::ios::binary);

	if(!file.is_open())
		throw std::exception(name_mvi.c_str());

	file.read((char*)&header, sizeof(header));

	items.clear();
	items.reserve(header.num_entries);
	imgdata.clear();
	imgdata.insert(imgdata.end(), header.height*header.width, 0);

	for(int counter = 0; counter < header.num_entries; counter++)
	{
		file.read((char*)&item, sizeof(item));
		items.push_back(item);
	}

	size_t payload_offset = ((file.tellg() / 2048) + 1) * 2048;
	file.seekg(payload_offset);

	current				= items.begin();
	name				= name_mvi;
	width				= header.width;
	height				= header.height;
	fps					= header.fps;
	has_audio			= header.has_audio == 1;
	audio_num_channels	= header.audio_num_channels;
	audio_samplerate	= header.audio_samplerate;
	audio_bits			= header.audio_bits;
}

void MVILoader::prefetch_sound(void)
{
	sounddata.clear();

	if(!has_audio)
		return;

	std::vector<unsigned char> left;
	std::vector<unsigned char> right;

	size_t payload_offset = file.tellg();
	file.seekg(payload_offset);

	for(std::vector<Item>::iterator	it = items.begin(); it != items.end(); it++)
	{
		switch(it->type)
		{
			case 5: //palette
			case 2: //video
			case 1: //video
			break;

			case 3: //leftchannel
			{
				char *in = new char[it->length];
				file.seekg(it->offset + payload_offset);
				file.read(in, it->length);
				left.insert(left.end(),in, in+it->length);
				delete[] in;
			}break;

			case 4: //rightchannel
			{
				char *in = new char[it->length];
				file.seekg(it->offset + payload_offset);
				file.read(in, it->length);
				right.insert(right.end(),in, in+it->length);
				delete[] in;
			}break;

			default:
				assert(false);
		}
	}
	
	std::vector<unsigned char>::iterator it_left	= left.begin();
	std::vector<unsigned char>::iterator it_right	= right.begin();

	sounddata.reserve((left.size() + right.size()) * 2);

	bool l,r;
	while((l = (it_left != left.end())) && (r = (it_right != right.end())) && (l || r))
	{
		if(l)
		{
			sounddata.push_back(0);
			sounddata.push_back(*it_left++);
		}
		if(r)
		{
			sounddata.push_back(0);
			sounddata.push_back(*it_right++);
		}
	}
	file.seekg(payload_offset);
}

void MVILoader::decode_next_frame(void)
{
	for(bool finished = false; !finished && current != items.end(); current++)
	{
		char *in = new char[current->length];
		file.read(in, current->length);

		switch(current->type)
		{
			case 5: //palette
			{
				unsigned char* ptr = reinterpret_cast<unsigned char*>(in);
				for(unsigned counter = 0; counter < 256; counter++)
				{
					size_t off = counter * 3 + (current->length == 772 ? 4 : 0);
					palette[counter] = 0xFF000000 | (ptr[off] << 16) | (ptr[off+1] << 8) | ptr[off+2];
				}//rest wird komplett ignoriert ->65k für nichts!
				
				finished = true;
			}break;

			case 1: //video
			{
				out.clear();
				out.reserve(height * width);
				
				Decoder decoder(in, out, 8*8);
				decoder.Decode();

				assert(decoder.in_offset/8 <= current->length && current->length <= (decoder.in_offset+decoder.CodeSize)/8);

				int pixel_step = (height * width) / out.size();

				for(int counter = 0; counter < height * width; counter++)
					imgdata[counter] = palette[out[counter/pixel_step]];
				
				finished = true;
			}break;

			case 2: //video
			{
				VideoDiffHead		head;
				VideoDiffSubHeader	subhead1;//wird ignoriert;
				VideoDiffSubHeader	subhead2;//wird ignoriert;
				std::vector<unsigned char> data1;
				std::vector<unsigned char> data2;

				size_t byte_offset = 0;

				memcpy(&head, in, sizeof(head));	byte_offset += sizeof(head);

				if(current->length == 16)
				{					
					finished = true;
					break;
				}
				memcpy(&subhead1, in + byte_offset, sizeof(subhead1));	byte_offset += sizeof(subhead1);

				{
					size_t length = head.num_payload1 - sizeof(subhead1);
					
					data1.reserve(length);
					Decoder decoder(in + byte_offset, data1);
					decoder.Decode();

					assert(decoder.in_offset/8 <= length && length <= (decoder.CodeSize+decoder.in_offset)/8);
					byte_offset += length;
				}

				if(head.num_payload2 < head.num_runlengths)
				{
					memcpy(&subhead2, in+byte_offset, sizeof(subhead2));	byte_offset += sizeof(subhead2);
					
					size_t length = head.num_payload2 - sizeof(subhead2);
					
					data2.reserve(length);
					Decoder decoder(in + byte_offset, data2);
					decoder.Decode();

					assert(decoder.in_offset/8 <= length && length <= (decoder.CodeSize+decoder.in_offset)/8);
					byte_offset += length;
				}
				else
				{
					data2.insert(data2.end(), in + byte_offset, in + byte_offset + head.num_payload2);
					byte_offset += head.num_payload2;
				}
				
				assert(current->length >= sizeof(head) + sizeof(subhead1));
				assert(current->length == sizeof(head) + head.num_payload1 + head.num_payload2);
				assert(head.num_payload1 == sizeof(subhead1) + subhead1.size_payload + 8);
				assert(head.num_payload2 == head.num_runlengths || head.num_payload2 == sizeof(subhead2) + subhead2.size_payload + 8);
				assert(head.num_payload2 == head.num_runlengths || head.num_runlengths == subhead2.num_unzipped);
				assert(head.num_colors == subhead1.num_unzipped);
				assert(head.num_colors == data1.size());
				assert(head.num_runlengths == data2.size());

				int color_offset	= 0;
				int pixel_step		= (height * width) / out.size();

				for(int counter = 0; counter < head.num_runlengths-1; counter++)
				{
					unsigned char bitfield = data2[counter];

					for(int shift = 0; bitfield;shift++)
					{
						if(bitfield & 128)
						{
							unsigned int color = palette[data1[color_offset++]];
							unsigned int pixel = (counter*8 + shift) * pixel_step;

							for(unsigned x = 0; x < pixel_step; x++)
								imgdata[pixel + x]	= color;
						}
						bitfield = bitfield << 1;
					}
				}

				finished = true;
			}break;

			case 3: //leftchannel
			case 4: //rightchannel
				break;

			default:
				assert(false);
		}
		delete[] in;
	}
}


Create a new paste based on this one


Comments: