//---------------------------------------------------------------------------
//	Video editor
//	2004 - 2007 Stanislav Sumec <sumec@fit.vutbr.cz>
//	Brno University of Technology
//	Faculty of Information Technology
//---------------------------------------------------------------------------

//---------------------------------------------------------------------------
#pragma hdrstop
#include "Sources.h"
#include "avfile.h"

//---------------------------------------------------------------------------
#pragma package(smart_init)

//---------------------------------------------------------------------------
TExtendedSource::TExtendedSource(): TImpExp::TSource()
{
	AVFile = NULL;
	AudioWrittenSamples = 0;
	AudioBufferSize = 0;
	AudioBuffer = NULL;
}

//---------------------------------------------------------------------------
TExtendedSource::~TExtendedSource()
{
	ClearBuffers();
	if (AudioBuffer)
	{
		delete[] AudioBuffer;
	}
	if (AVFile)
	{
		delete AVFile;
	}
}																

//---------------------------------------------------------------------------
void TExtendedSource::AllocBuffers(unsigned int Size)
{
	ClearBuffers();
	Buffers.resize(Size);
	for (unsigned int i = 0; i < Size; i++)
	{
		Buffers[i].Img = NULL;
		Buffers[i].Wave = NULL;
	}
}

//---------------------------------------------------------------------------
void TExtendedSource::ClearBuffers()
{
	TBuffers::iterator i = Buffers.begin();
	while (i != Buffers.end())
	{
		if (i->Img)
		{
			delete i->Img;
		}
		if (i->Wave)
		{
			delete i->Wave;
		}
		i++;
	}
	Buffers.clear();
}

//---------------------------------------------------------------------------
TExtendedSources::TExtendedSources()
{
}

//---------------------------------------------------------------------------
TExtendedSources::~TExtendedSources()
{
	clear();
}

//---------------------------------------------------------------------------
void TExtendedSources::push_back(TExtendedSource *Source)
{
	Sources.push_back(Source);
}

//---------------------------------------------------------------------------
void TExtendedSources::clear()
{
	std::vector<TExtendedSource*>::iterator i = Sources.begin();
	while (i != Sources.end())
	{
		delete (*i);
		i++;
	}
	Sources.clear();
}

//---------------------------------------------------------------------------
unsigned int TExtendedSources::size()
{
	return Sources.size();
}

//---------------------------------------------------------------------------
TExtendedSource* TExtendedSources::operator[](unsigned int Index)
{
	return Sources[Index];
}

//---------------------------------------------------------------------------
void TExtendedSources::Init(unsigned int Delay, EResize Resize)
{
	Time = 0;
	this->Delay = Delay;
	Actual = 0;
	this->Resize = Resize;

	std::vector<TExtendedSource*>::iterator i = Sources.begin();
	while (i != Sources.end())
	{
		TAVFile::TFrameInfo FI = (*i)->AVFile->GetFrameInfo();
		int Pos = TAVFile::Round((((double(Time) - double((*i)->Offset)) * double(FI.FrameRate.Rate)) / double(FI.FrameRate.Scale)) / 1000.0);
		if (Pos < 0)
		{
			Pos = 0;
		}
		(*i)->AVFile->Seek(Pos);

		(*i)->FrameRate = FI.FrameRate;
		(*i)->Width = FI.Width;
		(*i)->Height = FI.Height;
		if ((*i)->AVFile->GetOpenMode() == TAVFile::omRead && ((*i)->AVFile->GetOpenType() & TAVFile::otVideo))
		{
			(*i)->Length = (*i)->AVFile->GetVideoLength();
		}

		(*i)->AllocBuffers(Delay + 1);
		(*i)->AudioWrittenSamples = 0;
		(*i)->AudioBufferSize = 0;
		if ((*i)->AudioBuffer)
		{
			delete[] (*i)->AudioBuffer;
			(*i)->AudioBuffer = NULL;
		}

		// vynechani casti zvuku
		if ((*i)->AVFile->GetOpenMode() == TAVFile::omRead)
		{
			if (((*i)->AVFile->GetOpenType() & TAVFile::otAudio) && (*i)->AVFile->GetAudioPos() < (*i)->AVFile->GetAudioLength())
			{
				int Skew = (*i)->AVFile->GetAudioSkew();
				if (Skew < 0)
				{
					TAVFile::TAudioInfo AI = (*i)->AVFile->GetAudioInfo();
					unsigned int SkipSamples = ((long long)(-Skew) * AI.SamplesPerSec) / 1000;
					unsigned int ActualBufferSize = SkipSamples * 2 * AI.Channels;
					unsigned int AudioBufferSize = 0;
					BYTE *AudioBuffer = NULL;
					while (AudioBufferSize < ActualBufferSize && (*i)->AVFile->GetAudioPos() < (*i)->AVFile->GetAudioLength())
					{
						unsigned int SrcSize;
						BYTE *Src = (*i)->AVFile->GetAudio(SrcSize);

						unsigned int NewBufferSize = AudioBufferSize + SrcSize;
						BYTE *NewBuffer = new BYTE[NewBufferSize];
						if (AudioBuffer)
						{
							memcpy(NewBuffer, AudioBuffer, AudioBufferSize);
						}
						memcpy(NewBuffer + AudioBufferSize, Src, SrcSize);

						delete[] AudioBuffer;
						AudioBuffer = NewBuffer;
						AudioBufferSize = NewBufferSize;
					}

					if (AudioBuffer)
					{
						if (AudioBufferSize > ActualBufferSize)
						{
							(*i)->AudioBufferSize = AudioBufferSize - ActualBufferSize;
							(*i)->AudioBuffer = new BYTE[(*i)->AudioBufferSize];
							memcpy((*i)->AudioBuffer, AudioBuffer + ActualBufferSize, (*i)->AudioBufferSize);
						}
						delete[] AudioBuffer;
					}
				}
			}
		}
		i++;
	}
}

//---------------------------------------------------------------------------
void TExtendedSources::ReadActualFrame(TPSources::iterator i)
{
	bool Free = true;
	if ((*i)->AVFile->GetOpenMode() == TAVFile::omRead)
	{
		TAVFile::TFrameInfo FI = (*i)->AVFile->GetFrameInfo();
		int Pos = TAVFile::Round((((double(Time) - double((*i)->Offset)) * double(FI.FrameRate.Rate)) / double(FI.FrameRate.Scale)) / 1000.0);
		if (Pos < 0)
		{
			Pos = 0;
		}

		if (((*i)->AVFile->GetOpenType() & TAVFile::otVideo) && Pos >= 0)
		{
			if (Pos < (int)(*i)->AVFile->GetVideoLength())
			{
				int Skip = Pos - (*i)->AVFile->GetVideoPos();
				if (Skip > 0)
				{
					(*i)->AVFile->SkipFrames(Skip);
				}

				unsigned int Width, Height;
				ResizeDimension(FI.Width, FI.Height, Width, Height);

				if (!(*i)->Buffers[Actual].Img || (*i)->Buffers[Actual].Img->GetWidth() != Width || (*i)->Buffers[Actual].Img->GetHeight() != Height)
				{
					if ((*i)->Buffers[Actual].Img)
					{
						delete (*i)->Buffers[Actual].Img;
						(*i)->Buffers[Actual].Img = NULL;
					}
					(*i)->Buffers[Actual].Img = new TImg(Width, Height);
				}

				if (FI.Width == Width && FI.Height == Height)
				{
					if (Delay == 0)
					{
						(*i)->Buffers[Actual].Img->Create(Width, Height, (*i)->AVFile->GetFrame(Pos), false);
					}
					else
					{
						(*i)->AVFile->GetFrame((*i)->Buffers[Actual].Img->GetBitmap(), Pos);
					}
				}
				else
				{
					ResizeBitmap(FI.Width, FI.Height, Width, Height, (*i)->AVFile->GetFrame(Pos), (*i)->Buffers[Actual].Img->GetBitmap());
				}
				Free = false;
			}
			else if ((*i)->Loop != 0)
			{
#pragma message Pocitat Loop!
				Pos %= (*i)->AVFile->GetVideoLength();
				(*i)->AVFile->SeekVideo(Pos);

				unsigned int Width, Height;
				ResizeDimension(FI.Width, FI.Height, Width, Height);

				if (!(*i)->Buffers[Actual].Img || (*i)->Buffers[Actual].Img->GetWidth() != Width || (*i)->Buffers[Actual].Img->GetHeight() != Height)
				{
					if ((*i)->Buffers[Actual].Img)
					{
						delete (*i)->Buffers[Actual].Img;
						(*i)->Buffers[Actual].Img = NULL;
					}
					(*i)->Buffers[Actual].Img = new TImg(Width, Height);
				}

				if (FI.Width == Width && FI.Height == Height)
				{
					(*i)->AVFile->GetFrame((*i)->Buffers[Actual].Img->GetBitmap(), Pos);
				}
				else
				{
					ResizeBitmap(FI.Width, FI.Height, Width, Height, (*i)->AVFile->GetFrame(Pos), (*i)->Buffers[Actual].Img->GetBitmap());
				}
				Free = false;
			}
		}
	}
/*
	if (((*i)->AVFile->GetOpenType() & TAVFile::otVideo) && Pos >= 0 && Pos < (int)(*i)->AVFile->GetVideoLength())
	{
		int Skip = Pos - (*i)->AVFile->GetVideoPos();
		if (Skip > 0)
		{
			(*i)->AVFile->SkipFrames(Skip);
		}

		unsigned int Width, Height;
		ResizeDimension(FI.Width, FI.Height, Width, Height);

		if (!(*i)->Buffers[Actual].Img || (*i)->Buffers[Actual].Img->Width != Width || (*i)->Buffers[Actual].Img->Height != Height)
		{
			if ((*i)->Buffers[Actual].Img)
			{
				delete (*i)->Buffers[Actual].Img;
				(*i)->Buffers[Actual].Img = NULL;
			}
			(*i)->Buffers[Actual].Img = new TImg(Width, Height);
		}

		if (FI.Width == Width && FI.Height == Height)
		{
			(*i)->AVFile->GetFrame((*i)->Buffers[Actual].Img->Bitmap, Pos);
		}
		else
		{
			ResizeBitmap(FI.Width, FI.Height, Width, Height, (*i)->AVFile->GetFrame(Pos), (*i)->Buffers[Actual].Img->Bitmap);
		}
		Free = false;
	}
*/	
	if (Free && (*i)->Buffers[Actual].Img)
	{
		delete (*i)->Buffers[Actual].Img;
		(*i)->Buffers[Actual].Img = NULL;
	}
}

//---------------------------------------------------------------------------
void TExtendedSources::SkipActualFrame(TPSources::iterator i)
{
	if ((*i)->AVFile->GetOpenMode() == TAVFile::omRead)
	{
		TAVFile::TFrameInfo FI = (*i)->AVFile->GetFrameInfo();
		int Pos = TAVFile::Round((((double(Time) - double((*i)->Offset)) * double(FI.FrameRate.Rate)) / double(FI.FrameRate.Scale)) / 1000.0);
		if (Pos < 0)
		{
			Pos = 0;
		}

		if (((*i)->AVFile->GetOpenType() & TAVFile::otVideo) && Pos >= 0 && Pos < (int)(*i)->AVFile->GetVideoLength())
		{
			int Skip = Pos - (*i)->AVFile->GetVideoPos();
			if (Skip > 0)
			{
				(*i)->AVFile->SkipFrames(Skip);
			}
		}
	}
}

//---------------------------------------------------------------------------
void TExtendedSources::SkipFrame()
{
	if (Delay == 0)
	{
		for (TPSources::iterator i = Sources.begin(); i != Sources.end(); i++)
		{
			SkipActualFrame(i);
		}
	}
}

//---------------------------------------------------------------------------
void TExtendedSources::SetTime(int Time)
{
	if (Time < this->Time)
	{
		Init();
	}
	this->Time = Time;

	std::vector<TExtendedSource*>::iterator i = Sources.begin();
	while (i != Sources.end())
	{
		if ((*i)->Buffers[Actual].Wave)
		{
			delete (*i)->Buffers[Actual].Wave;
			(*i)->Buffers[Actual].Wave = NULL;
		}

		if (Delay > 0)
		{
			ReadActualFrame(i);
		}

		if ((*i)->AVFile->GetOpenMode() == TAVFile::omRead)
		{
			if (((*i)->AVFile->GetOpenType() & TAVFile::otAudio) && (*i)->AVFile->GetAudioPos() < (*i)->AVFile->GetAudioLength())
			{
				TAVFile::TAudioInfo AI = (*i)->AVFile->GetAudioInfo();
				unsigned int ActualSamples = ((long long)(Time) * AI.SamplesPerSec) / 1000;
				if ((*i)->AudioWrittenSamples < ActualSamples)
				{
					unsigned int ActualBufferSize = (ActualSamples - (*i)->AudioWrittenSamples) * 2 * AI.Channels;
					while ((*i)->AudioBufferSize < ActualBufferSize && (*i)->AVFile->GetAudioPos() < (*i)->AVFile->GetAudioLength())
					{
						unsigned int SrcSize;
						BYTE *Src = (*i)->AVFile->GetAudio(SrcSize);

						unsigned int NewBufferSize = (*i)->AudioBufferSize + SrcSize;
						BYTE *NewBuffer = new BYTE[NewBufferSize];
						if ((*i)->AudioBuffer)
						{
							memcpy(NewBuffer, (*i)->AudioBuffer, (*i)->AudioBufferSize);
						}
						memcpy(NewBuffer + (*i)->AudioBufferSize, Src, SrcSize);

						delete[] (*i)->AudioBuffer;
						(*i)->AudioBuffer = NewBuffer;
						(*i)->AudioBufferSize = NewBufferSize;
					}

					if ((*i)->AudioBufferSize >= ActualBufferSize)
					{
						(*i)->Buffers[Actual].Wave = new TWave(AI.Channels, AI.SamplesPerSec, ActualBufferSize, (*i)->AudioBuffer, true);
						(*i)->AudioWrittenSamples += ActualSamples - (*i)->AudioWrittenSamples;

						unsigned int NewBufferSize = (*i)->AudioBufferSize - ActualBufferSize;
						BYTE *NewBuffer = new BYTE[NewBufferSize];
						memcpy(NewBuffer, (*i)->AudioBuffer + ActualBufferSize, NewBufferSize);

						delete[] (*i)->AudioBuffer;
						(*i)->AudioBuffer = NewBuffer;
						(*i)->AudioBufferSize = NewBufferSize;
					}
				}
			}
		}

		i++;
	}
	Actual = (Actual + 1) % (Delay + 1);
}

//---------------------------------------------------------------------------
TExtendedSources::TPSources::iterator TExtendedSources::FindSource(int Camera)
{
	std::vector<TExtendedSource*>::iterator i = Sources.begin();
	while (i != Sources.end())
	{
		if ((*i)->Camera == Camera)
		{
			return i;
		}
		i++;
	}
	return i;
}

//---------------------------------------------------------------------------
TImg* TExtendedSources::GetFirstFrame(int Camera, int Number)
{
	if (Number < 0 || Number > (int)Delay)
	{
		return NULL;
	}

	TPSources::iterator i = FindSource(Camera);
	if (i != Sources.end())
	{
		if (Delay == 0)
		{
			ReadActualFrame(i);
		}
		return (*i)->Buffers[(Actual + Number + Delay + 1) % (Delay + 1)].Img;
	}
	else
	{
		return NULL;
	}
}

//---------------------------------------------------------------------------
TImg* TExtendedSources::GetLastFrame(int Camera, int Number)
{
	if (Number < 0 || Number > (int)Delay)
	{
		return NULL;
	}

	TPSources::iterator i = FindSource(Camera);
	if (i != Sources.end())
	{
		if (Delay == 0)
		{
			ReadActualFrame(i);
		}
		return (*i)->Buffers[(Actual - 1 - Number + Delay + 1) % (Delay + 1)].Img;
	}
	else
	{
		return NULL;
	}
}

//---------------------------------------------------------------------------
TWave* TExtendedSources::GetAudio(unsigned int Source)
{
	if (Source < Sources.size())
	{
		return Sources[Source]->Buffers[Actual].Wave;
	}
	else
	{
		return NULL;
	}
}

//---------------------------------------------------------------------------
unsigned int TExtendedSources::GetDelay()
{
	return Delay;
}

//---------------------------------------------------------------------------
bool TExtendedSources::GetFrameSize(unsigned int &Width, unsigned int &Height)
{
	TAVFile::TFrameInfo FI;
	FI.Width = 0;
	FI.Height = 0;
	bool VSExists = false;

	for (unsigned int i = 0; i < Sources.size(); i++)
	{
		TExtendedSource *Source = Sources[i];
		if (Source->AVFile && (Source->AVFile->GetOpenMode() == TAVFile::omRead) && (Source->AVFile->GetOpenType() & TAVFile::otVideo))
		{
			TAVFile::TFrameInfo SrcFI = Source->AVFile->GetFrameInfo();
			if (SrcFI.Width > FI.Width)
			{
				FI.Width = SrcFI.Width;
			}
			if (SrcFI.Height > FI.Height)
			{
				FI.Height = SrcFI.Height;
			}
			VSExists = true;
		}
	}
	if (VSExists)
	{
		ResizeDimension(FI.Width, FI.Height, Width, Height);
	}
	return VSExists;
}

//---------------------------------------------------------------------------
bool TExtendedSources::GetAudioPrms(unsigned int &Channels, unsigned int &SamplesPerSec)
{
	TAVFile::TAudioInfo AI;
	AI.Channels = 0;
	AI.SamplesPerSec = 0;
	bool ASExists = false;

	for (unsigned int i = 0; i < Sources.size(); i++)
	{
		TExtendedSource *Source = Sources[i];
		if (Source->AVFile && (Source->AVFile->GetOpenMode() == TAVFile::omRead) && (Source->AVFile->GetOpenType() & TAVFile::otAudio))
		{
			AI = Source->AVFile->GetAudioInfo();
			ASExists = true;
			break;
		}
	}
	if (ASExists)
	{
		Channels = AI.Channels;
		SamplesPerSec = AI.SamplesPerSec;
	}
	return ASExists;
}

//---------------------------------------------------------------------------
unsigned int TExtendedSources::GetLength()
{
	unsigned int Length = 0;
	std::vector<TExtendedSource*>::iterator i = Sources.begin();
	while (i != Sources.end())
	{
		if ((*i)->AVFile->GetOpenMode() == TAVFile::omRead)
		{
			if ((*i)->AVFile->GetOpenType() & TAVFile::otVideo)
			{
				TAVFile::TFrameInfo FI = (*i)->AVFile->GetFrameInfo();
				unsigned int l = 1000.0 * FI.FrameRate.Scale * (*i)->AVFile->GetVideoLength() / FI.FrameRate.Rate + (*i)->Offset;
				if (l > Length)
				{
					Length = l;
				}
			}
		}
		i++;
	}
	return Length;
}

//---------------------------------------------------------------------------
void TExtendedSources::ResizeDimension(unsigned int SrcWidth, unsigned int SrcHeight, unsigned int &DstWidth, unsigned int &DstHeight)
{
	switch (Resize)
	{
	case rHalf:
		DstWidth = SrcWidth / 2;
		DstHeight = SrcHeight / 2;
		break;

	case rQuarter:
		DstWidth = SrcWidth / 4;
		DstHeight = SrcHeight / 4;
		break;

	default:
		DstWidth = SrcWidth;
		DstHeight = SrcHeight;
		break;
	}
}

//---------------------------------------------------------------------------
void TExtendedSources::ResizeBitmap(unsigned int SrcWidth, unsigned int SrcHeight, unsigned int DstWidth, unsigned int DstHeight, BYTE *Src, BYTE *Dst)
{
	switch (Resize)
	{
	case rHalf:
		for (unsigned int y = 0; y < DstHeight; y++)
		{
			unsigned int *SrcLine = (unsigned int *)Src;
			unsigned int *DstLine = (unsigned int *)Dst;
			for (unsigned int x = 0; x < DstWidth; x++)
			{
				*DstLine = *SrcLine;
				DstLine += 1;
				SrcLine += 2;
			}
			Src += 4 * SrcWidth * 2;
			Dst += 4 * DstWidth;
		}
		break;

	case rQuarter:
		for (unsigned int y = 0; y < DstHeight; y++)
		{
			unsigned int *SrcLine = (unsigned int *)Src;
			unsigned int *DstLine = (unsigned int *)Dst;
			for (unsigned int x = 0; x < DstWidth; x++)
			{
				*DstLine = *SrcLine;
				DstLine += 1;
				SrcLine += 4;
			}
			Src += 4 * SrcWidth * 4;
			Dst += 4 * DstWidth;
		}
		break;
	}
}

//---------------------------------------------------------------------------
bool TExtendedSources::Eof()
{
	std::vector<TExtendedSource*>::iterator i = Sources.begin();
	while (i != Sources.end())
	{
		if ((*i)->Loop == 0 && (*i)->AVFile->GetOpenMode() == TAVFile::omRead)
		{
			if ((*i)->AVFile->GetOpenType() & TAVFile::otVideo)
			{
				if ((*i)->AVFile->GetVideoPos() < (*i)->AVFile->GetVideoLength())
				{
					return false;
				}
			}
		}
		i++;
	}
	return true;
}

