// must not be called in the ctor, can throw exceptions
	void MemoryDataSource::_loadFile()
	{
		if (this->data == NULL)
		{
			VideoClip::Format format;
			FILE* file = openSupportedFormatFile(filename, format, this->fullFilename);
			if (file == NULL)
			{
				std::string message = "Can't open or find video file: " + filename;
				log(message);
				throw TheoraplayerException(message);
			}
			this->formatName = format.name;
#ifdef _WIN32
			struct _stat64 s;
			_fstati64(_fileno(file), &s);
#else
			struct stat s;
			fstat(fileno(file), &s);
#endif
			this->size = (int64_t)s.st_size;
			if (this->size > 0xFFFFFFFF)
			{
				fclose(file);
				throw TheoraplayerException("MemoryDataSource doesn't support files larger than 4GB!");
			}
			if (this->size < UINT_MAX)
			{
				this->data = new unsigned char[(unsigned int)this->size];
				fread(this->data, 1, (size_t)this->size, file);
			}
			else
			{
				fclose(file);
				throw TheoraplayerException("Unable to preload file to memory, file is too large.");
			}
			fclose(file);
		}
	}
	void FileDataSource::_openFile()
	{
		if (this->filePtr == NULL)
		{
			VideoClip::Format format;
			this->filePtr = openSupportedFormatFile(this->filename, format, this->fullFilename);
			if (this->filePtr == NULL)
			{
				std::string message = "Can't open or find video file: " + filename;
				log(message);
				throw TheoraplayerException(message);
			}
			this->formatName = format.name;
#ifdef _WIN32
			struct _stat64 s;
			_fstati64(_fileno(this->filePtr), &s);
#else
			struct stat s;
			fstat(fileno(this->filePtr), &s);
#endif
			this->length = (int64_t)s.st_size;
		}
	}
	void VideoClip_Theora::_readTheoraVorbisHeaders()
	{
		ogg_packet tempOggPacket;
		//init Vorbis/Theora Layer
		//Ensure all structures get cleared out.
		memset(&this->info.OggSyncState, 0, sizeof(ogg_sync_state));
		memset(&this->info.OggPage, 0, sizeof(ogg_page));
		memset(&this->info.VorbisStreamState, 0, sizeof(ogg_stream_state));
		memset(&this->info.TheoraStreamState, 0, sizeof(ogg_stream_state));
		memset(&this->info.TheoraInfo, 0, sizeof(th_info));
		memset(&this->info.TheoraComment, 0, sizeof(th_comment));
		memset(&this->info.VorbisInfo, 0, sizeof(vorbis_info));
		memset(&this->info.VorbisDSPState, 0, sizeof(vorbis_dsp_state));
		memset(&this->info.VorbisBlock, 0, sizeof(vorbis_block));
		memset(&this->info.VorbisComment, 0, sizeof(vorbis_comment));
		// init all structures
		ogg_sync_init(&this->info.OggSyncState);
		th_comment_init(&this->info.TheoraComment);
		th_info_init(&this->info.TheoraInfo);
		vorbis_info_init(&this->info.VorbisInfo);
		vorbis_comment_init(&this->info.VorbisComment);
		// start
		ogg_stream_state oggStateTest;
		bool decodeAudio = (theoraplayer::manager->getAudioInterfaceFactory() != NULL);
		char* buffer = NULL;
		int bytesRead = 0;
		bool done = false;
		while (!done)
		{
			buffer = ogg_sync_buffer(&this->info.OggSyncState, BUFFER_SIZE);
			bytesRead = this->stream->read(buffer, BUFFER_SIZE);
			ogg_sync_wrote(&this->info.OggSyncState, bytesRead);
			if (bytesRead == 0)
			{
				break;
			}
			while (ogg_sync_pageout(&this->info.OggSyncState, &this->info.OggPage) > 0)
			{
				memset(&oggStateTest, 0, sizeof(oggStateTest));
				//is this an initial header? If not, stop
				if (ogg_page_bos(&this->info.OggPage) == 0)
				{
					//This is done blindly, because stream only accept themselves
					if (this->theoraStreams > 0)
					{
						ogg_stream_pagein(&this->info.TheoraStreamState, &this->info.OggPage);
					}
					if (this->vorbisStreams > 0)
					{
						ogg_stream_pagein(&this->info.VorbisStreamState, &this->info.OggPage);
					}
					done = true;
					break;
				}
				ogg_stream_init(&oggStateTest, ogg_page_serialno(&this->info.OggPage));
				ogg_stream_pagein(&oggStateTest, &this->info.OggPage);
				ogg_stream_packetout(&oggStateTest, &tempOggPacket);
				// identify the codec
				if (this->theoraStreams == 0 && th_decode_headerin(&this->info.TheoraInfo, &this->info.TheoraComment, &this->info.TheoraSetup, &tempOggPacket) > 0)
				{
					// This is the Theora Header
					memcpy(&this->info.TheoraStreamState, &oggStateTest, sizeof(oggStateTest));
					this->theoraStreams = 1;
				}
				else if (decodeAudio && this->vorbisStreams == 0 && vorbis_synthesis_headerin(&this->info.VorbisInfo, &this->info.VorbisComment, &tempOggPacket) >= 0)
				{
					// This is vorbis header
					memcpy(&this->info.VorbisStreamState, &oggStateTest, sizeof(oggStateTest));
					this->vorbisStreams = 1;
				}
				else // Hm, guess it's not a header we support, so erase it
				{
					ogg_stream_clear(&oggStateTest);
				}
			}
		}
		int result = 0;
		while ((this->theoraStreams > 0 && this->theoraStreams < 3) || (this->vorbisStreams && this->vorbisStreams < 3))
		{
			// Check 2nd'dary headers... Theora First
			while (this->theoraStreams > 0 && this->theoraStreams < 3 && (result = ogg_stream_packetout(&this->info.TheoraStreamState, &tempOggPacket)))
			{
				if (result < 0)
				{
					throw TheoraplayerException("Error parsing Theora stream headers!");
				}
				if (th_decode_headerin(&this->info.TheoraInfo, &this->info.TheoraComment, &this->info.TheoraSetup, &tempOggPacket) == 0)
				{
					throw TheoraplayerException("Invalid theora stream!");
				}
				++this->theoraStreams;
			} // end while looking for more theora headers
			  // look 2nd vorbis header packets
			while (this->vorbisStreams < 3 && (result = ogg_stream_packetout(&this->info.VorbisStreamState, &tempOggPacket)))
			{
				if (result < 0)
				{
					throw TheoraplayerException("Error parsing vorbis stream headers!");
				}
				if (vorbis_synthesis_headerin(&this->info.VorbisInfo, &this->info.VorbisComment, &tempOggPacket) != 0)
				{
					throw TheoraplayerException("Invalid stream!");
				}
				++this->vorbisStreams;
			} // end while looking for more vorbis headers
			  // Not finished with Headers, get some more file data
			if (ogg_sync_pageout(&this->info.OggSyncState, &this->info.OggPage) > 0)
			{
				if (this->theoraStreams > 0)
				{
					ogg_stream_pagein(&this->info.TheoraStreamState, &this->info.OggPage);
				}
				if (this->vorbisStreams > 0)
				{
					ogg_stream_pagein(&this->info.VorbisStreamState, &this->info.OggPage);
				}
			}
			else
			{
				buffer = ogg_sync_buffer(&this->info.OggSyncState, BUFFER_SIZE);
				bytesRead = this->stream->read(buffer, BUFFER_SIZE);
				ogg_sync_wrote(&this->info.OggSyncState, bytesRead);
				if (bytesRead == 0)
				{
					throw TheoraplayerException("End of file found prematurely!");
				}
			}
		} // end while looking for all headers
		  //log("Vorbis Headers: " + str(mVorbisHeaders) + " Theora Headers : " + str(mTheoraHeaders));
	}