// This file is part of ZetaGlest <https://github.com/ZetaGlest>
//
// Copyright (C) 2018  The ZetaGlest team
//
// ZetaGlest is a fork of MegaGlest <https://megaglest.org>
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.

// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>

#include <GL/glew.h>
#include "video_player.h"
#include <SDL.h>
#include <SDL_mutex.h>
#include <vector>
#include <time.h>

#if defined(WIN32)
#include <windows.h>
#endif

#ifdef HAS_LIBVLC

//MSVC++ 11.0 _MSC_VER = 1700 (Visual Studio 2011)
//MSVC++ 10.0 _MSC_VER = 1600 (Visual Studio 2010)
//MSVC++ 9.0  _MSC_VER = 1500 (Visual Studio 2008)
#if defined(_MSC_VER) && _MSC_VER < 1600

// Older versions of VC++ don't include stdint.h
typedef __int32 int32_t;
typedef unsigned __int32 uint32_t;
typedef __int64 int64_t;
typedef unsigned __int64 uint64_t;

#endif

#include <vlc/vlc.h>
#endif


#if defined(WIN32)
/**
* @param location The location of the registry key. For example "Software\\Bethesda Softworks\\Morrowind"
* @param name the name of the registry key, for example "Installed Path"
* @return the value of the key or an empty string if an error occured.
*/
std::string getRegKey(const std::string& location, const std::string& name) {
	HKEY key;
	CHAR value[1024];
	DWORD bufLen = 1024 * sizeof(CHAR);
	long ret;
	ret = RegOpenKeyExA(HKEY_LOCAL_MACHINE, location.c_str(), 0, KEY_QUERY_VALUE, &key);
	if (ret != ERROR_SUCCESS) {
		return std::string();
	}
	ret = RegQueryValueExA(key, name.c_str(), 0, 0, (LPBYTE) value, &bufLen);
	RegCloseKey(key);
	if ((ret != ERROR_SUCCESS) || (bufLen > 1024 * sizeof(TCHAR))) {
		return std::string();
	}
	string stringValue = value;
	size_t i = stringValue.length();
	while (i > 0 && stringValue[i - 1] == '\0') {
		--i;
	}
	return stringValue.substr(0, i);
}
#endif

const string HTTP_PREFIX = "http";
#ifdef HAS_LIBVLC
const double MAX_VIDEO_START_MILLISECONDS = 10.0;
#endif

class ctx {
public:
	ctx() {
		loadingCB = NULL;
		empty = NULL;
		textureId = 0; // Texture ID
		surf = NULL;
		mutex = NULL;
		x = 0;
		y = 0;
		width = 0;
		height = 0;
		rawData = NULL;
		started = false;
		error = false;
		stopped = false;
		end_of_media = false;
		isPlaying = 0;
		needToQuit = false;
		verboseEnabled = 0;

#ifdef HAS_LIBVLC
		libvlc = NULL;
		m = NULL;
		mp = NULL;
		ml = NULL;
		mlp = NULL;

		vlc_argv.clear();
		vlc_argv_str.clear();
#endif
	}

	Shared::Graphics::VideoLoadingCallbackInterface *loadingCB;
	SDL_Surface *empty;
	GLuint textureId; // Texture ID
	SDL_Surface *surf;
	SDL_mutex *mutex;
	int x;
	int y;
	int width;
	int height;
	void *rawData;
	bool started;
	bool error;
	bool stopped;
	bool end_of_media;
	bool isPlaying;
	bool needToQuit;
	bool verboseEnabled;

#ifdef HAS_LIBVLC
	libvlc_instance_t *libvlc;
	libvlc_media_t *m;
	libvlc_media_player_t *mp;

	libvlc_media_list_t *ml;
	libvlc_media_list_player_t *mlp;

	std::vector<const char *> vlc_argv;
	std::vector<string> vlc_argv_str;
#endif
};

namespace Shared {
	namespace Graphics {

		bool VideoPlayer::disabled = false;

		// Load a texture
		static inline void loadTexture(class ctx *ctx) {
			if (ctx->verboseEnabled) printf("In [%s] Line: %d\n", __FUNCTION__, __LINE__);

			void *rawData = ctx->rawData;
			Uint8 * pixelSource = 0;
			Uint8 * pixelDestination = (Uint8 *) rawData;
			Uint32 pix = 0;

			for (int i = ctx->height; i > 0; i--) {
				for (int j = 0; j < ctx->width; j++) {
					pixelSource = (Uint8 *) ctx->surf->pixels + (i - 1) * ctx->surf->pitch + j * 2;
					pix = *(Uint16 *) pixelSource;
					SDL_GetRGBA(pix, ctx->surf->format, &(pixelDestination[0]), &(pixelDestination[1]), &(pixelDestination[2]), &(pixelDestination[3]));
					pixelDestination += 4;
				}
			}

			// Building the texture
			glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
			glBindTexture(GL_TEXTURE_2D, ctx->textureId);
			glTexImage2D(GL_TEXTURE_2D, 0, 4, ctx->width, ctx->height, 0, GL_RGBA, GL_UNSIGNED_BYTE, (Uint8 *) rawData);
		}

#ifdef HAS_LIBVLC
#if !defined(LIBVLC_VERSION_PRE_2) && !defined(LIBVLC_VERSION_PRE_1_1_0)
		static void *lock(void *data, void **p_pixels) {
			class ctx *ctx = (class ctx *)data;
			if (ctx->verboseEnabled) printf("In [%s] Line: %d\n", __FUNCTION__, __LINE__);

			SDL_LockMutex(ctx->mutex);
			SDL_LockSurface(ctx->surf);
			*p_pixels = ctx->surf->pixels;

			return NULL; /* picture identifier, not needed here */
		}

		static void unlock(void *data, void *id, void *const *p_pixels) {
			class ctx *ctx = (class ctx *)data;
			if (ctx->verboseEnabled) printf("In [%s] Line: %d\n", __FUNCTION__, __LINE__);

			/* VLC just rendered the video, but we can also render stuff */
			SDL_UnlockSurface(ctx->surf);
			SDL_UnlockMutex(ctx->mutex);
		}

		static void display(void *data, void *id) {
			// VLC wants to display the video
			class ctx *ctx = (class ctx *)data;
			if (ctx->verboseEnabled) printf("In [%s] Line: %d\n", __FUNCTION__, __LINE__);
		}
#endif
#endif

#if defined(HAS_LIBVLC) && defined(LIBVLC_VERSION_PRE_2) && defined(LIBVLC_VERSION_PRE_1_1_0)
		static void catchError(libvlc_exception_t *ex) {
			if (libvlc_exception_raised(ex)) {
				fprintf(stderr, "exception: %s\n", libvlc_exception_get_message(ex));
				//exit(1);
			}

			libvlc_exception_clear(ex);
		}
#endif

#if defined(HAS_LIBVLC)

		/*
		void trapPlayingEvent(const libvlc_event_t *evt, void *data) {
			class ctx *ctx = (class ctx *)data;
			if(ctx->verboseEnabled) printf("In [%s] Line: %d\n",__FUNCTION__,__LINE__);
			ctx->isPlaying = true;
			ctx->started = true;
		}

		void trapEndReachedEvent(const libvlc_event_t *evt, void *data) {
			class ctx *ctx = (class ctx *)data;
			if(ctx->verboseEnabled) printf("In [%s] Line: %d\n",__FUNCTION__,__LINE__);
			ctx->isPlaying = false;
		}

		void trapBufferingEvent(const libvlc_event_t *evt, void *data) {
			class ctx *ctx = (class ctx *)data;
			if(ctx->verboseEnabled) printf("In [%s] Line: %d\n",__FUNCTION__,__LINE__);
			ctx->isPlaying = true;
		}

		void trapErrorEvent(const libvlc_event_t *evt, void *data) {
			class ctx *ctx = (class ctx *)data;
			if(ctx->verboseEnabled) printf("In [%s] Line: %d\n",__FUNCTION__,__LINE__);
			ctx->isPlaying = false;
		}
		*/
		void callbacks(const libvlc_event_t* event, void* data) {
			class ctx *ctx = (class ctx *)data;
			if (ctx->verboseEnabled) printf("In [%s] Line: %d event [%d]\n", __FUNCTION__, __LINE__, event->type);
			switch (event->type) {
				case libvlc_MediaPlayerPlaying:
					if (ctx->verboseEnabled) printf("libvlc_MediaPlayerPlaying\n");
					ctx->end_of_media = false;
					ctx->error = false;
					ctx->stopped = false;
					ctx->isPlaying = true;
					ctx->started = true;

					break;
				case libvlc_MediaPlayerPaused:
					if (ctx->verboseEnabled) printf("libvlc_MediaPlayerPaused\n");
					break;
				case libvlc_MediaPlayerStopped:
					if (ctx->verboseEnabled) printf("libvlc_MediaPlayerStopped\n");
					ctx->stopped = true;

					break;
				case libvlc_MediaPlayerEndReached:
					if (ctx->verboseEnabled) printf("libvlc_MediaPlayerEndReached\n");
					if (ctx->started == true && ctx->error == false) {
						ctx->isPlaying = false;
					}

					ctx->end_of_media = true;

					break;
				case libvlc_MediaPlayerTimeChanged:
					if (ctx->verboseEnabled) printf("libvlc_MediaPlayerTimeChanged\n");
					break;
				case libvlc_MediaPlayerPositionChanged:
					//qDebug() << self << "position changed : " << event->u.media_player_position_changed.new_position;
					//self->emit positionChanged( event->u.media_player_position_changed.new_position );
					if (ctx->verboseEnabled) printf("libvlc_MediaPlayerPositionChanged\n");
					break;
				case libvlc_MediaPlayerLengthChanged:
					if (ctx->verboseEnabled) printf("libvlc_MediaPlayerLengthChanged\n");
					break;
				case libvlc_MediaPlayerSnapshotTaken:
					if (ctx->verboseEnabled) printf("libvlc_MediaPlayerSnapshotTaken\n");
					break;
				case libvlc_MediaPlayerEncounteredError:
					if (ctx->verboseEnabled) printf("libvlc_MediaPlayerEncounteredError\n");
					if (ctx->started == false) {
						ctx->isPlaying = false;
					}
					ctx->error = true;


					break;
				case libvlc_MediaPlayerSeekableChanged:
					if (ctx->verboseEnabled) printf("libvlc_MediaPlayerSeekableChanged\n");
					break;
				case libvlc_MediaPlayerPausableChanged:
					if (ctx->verboseEnabled) printf("libvlc_MediaPlayerPausableChanged\n");
					break;
				case libvlc_MediaPlayerTitleChanged:
					if (ctx->verboseEnabled) printf("libvlc_MediaPlayerTitleChanged\n");
					break;
				case libvlc_MediaPlayerNothingSpecial:
					if (ctx->verboseEnabled) printf("libvlc_MediaPlayerNothingSpecial\n");
					break;
				case libvlc_MediaPlayerOpening:
					if (ctx->verboseEnabled) printf("libvlc_MediaPlayerOpening\n");
					break;
				case libvlc_MediaPlayerBuffering:
					if (ctx->verboseEnabled) printf("libvlc_MediaPlayerBuffering\n");
					break;
				case libvlc_MediaPlayerForward:
					if (ctx->verboseEnabled) printf("libvlc_MediaPlayerForward\n");
					break;
				case libvlc_MediaPlayerBackward:
					if (ctx->verboseEnabled) printf("libvlc_MediaPlayerBackward\n");
					break;
				case libvlc_MediaStateChanged:
					if (ctx->verboseEnabled) printf("libvlc_MediaStateChanged\n");
					break;
				case libvlc_MediaParsedChanged:
					if (ctx->verboseEnabled) printf("libvlc_MediaParsedChanged\n");
					break;

#if defined(LIBVLC_VERSION_PRE_2) && defined(LIBVLC_VERSION_PRE_1_1_0)
				case libvlc_MediaPlayerVout:
					if (ctx->verboseEnabled) printf("libvlc_MediaPlayerVout\n");
					break;
#endif
				case libvlc_MediaListItemAdded:
					if (ctx->verboseEnabled) printf("libvlc_MediaListItemAdded\n");
					break;
				case libvlc_MediaListWillAddItem:
					if (ctx->verboseEnabled) printf("libvlc_MediaListWillAddItem\n");
					break;
				case libvlc_MediaListItemDeleted:
					if (ctx->verboseEnabled) printf("libvlc_MediaListItemDeleted\n");
					break;
				case libvlc_MediaListWillDeleteItem:
					if (ctx->verboseEnabled) printf("libvlc_MediaListWillDeleteItem\n");
					break;
				case libvlc_MediaListViewItemAdded:
					if (ctx->verboseEnabled) printf("libvlc_MediaListViewItemAdded\n");
					break;
				case libvlc_MediaListViewWillAddItem:
					if (ctx->verboseEnabled) printf("libvlc_MediaListViewWillAddItem\n");
					break;
				case libvlc_MediaListViewItemDeleted:
					if (ctx->verboseEnabled) printf("libvlc_MediaListViewItemDeleted\n");
					break;
				case libvlc_MediaListViewWillDeleteItem:
					if (ctx->verboseEnabled) printf("libvlc_MediaListViewWillDeleteItem\n");
					break;
				case libvlc_MediaListPlayerPlayed:
					if (ctx->verboseEnabled) printf("libvlc_MediaListPlayerPlayed\n");
					break;
				case libvlc_MediaListPlayerNextItemSet:
					if (ctx->verboseEnabled) printf("libvlc_MediaListPlayerNextItemSet\n");
					//ctx->isPlaying = true;
					//ctx->started = true;
					ctx->end_of_media = false;
					ctx->error = false;
					ctx->stopped = false;

					break;
				case libvlc_MediaListPlayerStopped:
					if (ctx->verboseEnabled) printf("libvlc_MediaListPlayerStopped\n");
					ctx->stopped = true;

					break;

				case libvlc_MediaDiscovererStarted:
					if (ctx->verboseEnabled) printf("libvlc_MediaDiscovererStarted\n");
					break;
				case libvlc_MediaDiscovererEnded:
					if (ctx->verboseEnabled) printf("libvlc_MediaDiscovererEndedvvvvvvvvv\n");
					break;
				case libvlc_VlmMediaAdded:
					if (ctx->verboseEnabled) printf("libvlc_VlmMediaAdded\n");
					break;
				case libvlc_VlmMediaRemoved:
					if (ctx->verboseEnabled) printf("libvlc_VlmMediaRemoved\n");
					break;
				case libvlc_VlmMediaChanged:
					if (ctx->verboseEnabled) printf("libvlc_VlmMediaChanged\n");
					break;
				case libvlc_VlmMediaInstanceStarted:
					if (ctx->verboseEnabled) printf("libvlc_VlmMediaInstanceStarted\n");
					break;
				case libvlc_VlmMediaInstanceStopped:
					if (ctx->verboseEnabled) printf("libvlc_VlmMediaInstanceStopped\n");
					ctx->stopped = true;

					break;
				case libvlc_VlmMediaInstanceStatusInit:
					if (ctx->verboseEnabled) printf("libvlc_VlmMediaInstanceStatusInit\n");
					break;
				case libvlc_VlmMediaInstanceStatusOpening:
					if (ctx->verboseEnabled) printf("libvlc_VlmMediaInstanceStatusOpening\n");
					break;
				case libvlc_VlmMediaInstanceStatusPlaying:
					if (ctx->verboseEnabled) printf("libvlc_VlmMediaInstanceStatusPlaying\n");
					break;
				case libvlc_VlmMediaInstanceStatusPause:
					if (ctx->verboseEnabled) printf("libvlc_VlmMediaInstanceStatusPause\n");
					break;
				case libvlc_VlmMediaInstanceStatusEnd:
					if (ctx->verboseEnabled) printf("libvlc_VlmMediaInstanceStatusEnd\n");
					break;
				case libvlc_VlmMediaInstanceStatusError:
					if (ctx->verboseEnabled) printf("libvlc_VlmMediaInstanceStatusError\n");
					break;

				default:
					//        qDebug() << "Unknown mediaPlayerEvent: " << event->type;
					break;
			}
		}

#endif

		VideoPlayer::VideoPlayer(VideoLoadingCallbackInterface *loadingCB,
			string filename,
			string filenameFallback,
			SDL_Window *window,
			int x, int y, int width, int height, int colorBits,
			bool loop, string pluginsPath, bool verboseEnabled)
			: ctxPtr(NULL) {

			this->loadingCB = loadingCB;
			this->filename = filename;
			this->filenameFallback = filenameFallback;
			this->window = window;
			this->x = x;
			this->y = y;
			this->width = width;
			this->height = height;
			this->colorBits = colorBits;
			this->loop = loop;
			this->pluginsPath = pluginsPath;
			//this->verboseEnabled = true;
			this->verboseEnabled = verboseEnabled;
			this->stop = false;
			this->finished = false;
			this->successLoadingLib = false;

			init();
		}

		void VideoPlayer::init() {
			if (VideoPlayer::disabled == true) {
				return;
			}
			cleanupPlayer();
			ctxPtr = new ctx();
			ctxPtr->loadingCB = loadingCB;
			ctxPtr->x = x;
			ctxPtr->y = y;
			ctxPtr->width = width;
			ctxPtr->height = height;
			ctxPtr->rawData = (void *) malloc(width * height * 4);
			ctxPtr->verboseEnabled = verboseEnabled;
		}

		VideoPlayer::~VideoPlayer() {
			cleanupPlayer();
		}

		bool VideoPlayer::hasBackEndVideoPlayer() {
			if (VideoPlayer::disabled == true) {
				return false;
			}

#ifdef HAS_LIBVLC
			return true;
#else
			return false;
#endif
		}

		void VideoPlayer::cleanupPlayer() {
			if (ctxPtr != NULL) {
				if (ctxPtr->rawData != NULL) {
					free(ctxPtr->rawData);
					ctxPtr->rawData = NULL;
				}

				delete ctxPtr;
				ctxPtr = NULL;
			}
		}

		bool VideoPlayer::initPlayer(string mediaURL) {
			if (VideoPlayer::disabled == true) {
				return true;
			}

#ifdef HAS_LIBVLC
			ctxPtr->libvlc = NULL;
			ctxPtr->m = NULL;
			ctxPtr->mp = NULL;
			ctxPtr->vlc_argv.clear();
			ctxPtr->vlc_argv.push_back("--intf=dummy");
			//ctxPtr->vlc_argv.push_back("--intf=http");
			//ctxPtr->vlc_argv.push_back("--no-media-library");
			ctxPtr->vlc_argv.push_back("--ignore-config"); /* Don't use VLC's config */
			ctxPtr->vlc_argv.push_back("--no-xlib"); /* tell VLC to not use Xlib */
			ctxPtr->vlc_argv.push_back("--no-video-title-show");
			//ctxPtr->vlc_argv.push_back("--network-caching=10000");

			if (loop == true) {
				ctxPtr->vlc_argv.push_back("--loop");
				ctxPtr->vlc_argv.push_back("--repeat");
			}

#if defined(LIBVLC_VERSION_PRE_2)
			ctxPtr->vlc_argv_str.push_back("--plugin-path=" + pluginsPath);
			ctxPtr->vlc_argv.push_back(ctxPtr->vlc_argv_str[ctxPtr->vlc_argv_str.size() - 1].c_str());
#endif

#if defined(LIBVLC_VERSION_PRE_2) && defined(LIBVLC_VERSION_PRE_1_1_0)
			char clock[64], cunlock[64], cdata[64];
			char cwidth[32], cheight[32], cpitch[32];
			/*
				 *  Initialise libVLC
			 */
			sprintf(clock, "%lld", (long long int)(intptr_t)lock);
			sprintf(cunlock, "%lld", (long long int)(intptr_t)unlock);
			sprintf(cdata, "%lld", (long long int)(intptr_t)ctxPtr);
			sprintf(cwidth, "%i", width);
			sprintf(cheight, "%i", height);
			sprintf(cpitch, "%i", colorBits);

			vlc_argv.push_back("--vout");
			vlc_argv.push_back("vmem");
			vlc_argv.push_back("--vmem-width");
			ctxPtr->vlc_argv_str.push_back(cwidth);
			ctxPtr->vlc_argv.push_back(ctxPtr->vlc_argv_str[ctxPtr->vlc_argv_str.size() - 1].c_str());
			vlc_argv.push_back("--vmem-height");
			ctxPtr->vlc_argv_str.push_back(cheight);
			ctxPtr->vlc_argv.push_back(ctxPtr->vlc_argv_str[ctxPtr->vlc_argv_str.size() - 1].c_str());
			vlc_argv.push_back("--vmem-pitch");
			ctxPtr->vlc_argv_str.push_back(cpitch);
			ctxPtr->vlc_argv.push_back(ctxPtr->vlc_argv_str[ctxPtr->vlc_argv_str.size() - 1].c_str());
			vlc_argv.push_back("--vmem-chroma");
			vlc_argv.push_back("RV16");
			vlc_argv.push_back("--vmem-lock");
			ctxPtr->vlc_argv_str.push_back(clock);
			ctxPtr->vlc_argv.push_back(ctxPtr->vlc_argv_str[ctxPtr->vlc_argv_str.size() - 1].c_str());
			vlc_argv.push_back("--vmem-unlock");
			ctxPtr->vlc_argv_str.push_back(cunlock);
			ctxPtr->vlc_argv.push_back(ctxPtr->vlc_argv_str[ctxPtr->vlc_argv_str.size() - 1].c_str());
			vlc_argv.push_back("--vmem-data");
			ctxPtr->vlc_argv_str.push_back(cdata);
			ctxPtr->vlc_argv.push_back(ctxPtr->vlc_argv_str[ctxPtr->vlc_argv_str.size() - 1].c_str());

#endif

			if (verboseEnabled) ctxPtr->vlc_argv.push_back("--verbose=2");
			if (verboseEnabled) ctxPtr->vlc_argv.push_back("--extraintf=logger"); //log anything
#if defined(WIN32)
			if (verboseEnabled) _putenv("VLC_VERBOSE=2");
#endif


			//	char const *vlc_argv[] =
			//	{
			//		//"--no-audio", /* skip any audio track */
			//		"--no-xlib", /* tell VLC to not use Xlib */
			//		"--no-video-title-show",
			//		pluginParam.c_str(),
			//	};
			//	int vlc_argc = sizeof(vlc_argv) / sizeof(*vlc_argv);
#endif

			ctxPtr->empty = NULL;
			glEnable(GL_TEXTURE_2D);
			glEnable(GL_DEPTH_TEST);
			// Init Texture
			glGenTextures(1, &ctxPtr->textureId);
			glBindTexture(GL_TEXTURE_2D, ctxPtr->textureId);
			glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
			glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

			ctxPtr->empty = SDL_CreateRGBSurface(SDL_SWSURFACE, width, height,
				colorBits, 0, 0, 0, 0);
			ctxPtr->surf = SDL_CreateRGBSurface(SDL_SWSURFACE, width, height,
				colorBits, 0x001f, 0x07e0, 0xf800, 0);
			ctxPtr->mutex = SDL_CreateMutex();

#ifdef HAS_LIBVLC
			/*
			 *  Initialize libVLC
			 */
			if (verboseEnabled) printf("Trying [%s]\n", getenv("VLC_PLUGIN_PATH"));

#if defined(LIBVLC_VERSION_PRE_2) && defined(LIBVLC_VERSION_PRE_1_1_0)
			libvlc_exception_t ex;
			libvlc_exception_init(&ex);

			ctxPtr->libvlc = libvlc_new(ctxPtr->vlc_argc, &ctxPtr->vlc_argv[0], &ex);
			catchError(&ex);
#else
			int vlc_argc = ctxPtr->vlc_argv.size();
			ctxPtr->libvlc = libvlc_new(vlc_argc, &ctxPtr->vlc_argv[0]);
#endif

			if (verboseEnabled) printf("In [%s] Line: %d, libvlc [%p]\n", __FUNCTION__, __LINE__, ctxPtr->libvlc);

			/* It is meaningless to try all this because we have to restart the game to pickup new env vars
			#if defined(WIN32)
				if(libvlc == NULL) {
					// For windows check registry for install path
					std::string strValue = getRegKey("Software\\VideoLAN\\VLC", "InstallDir");
					if(strValue != "") {
						if(strValue.length() >= 2) {
							if(strValue[0] == '"') {
								strValue = strValue.erase(0);
							}
							if(strValue[strValue.length()-1] == '"') {
								strValue = strValue.erase(strValue.length()-1);
							}
						}
						strValue = "VLC_PLUGIN_PATH=" + strValue;
						_putenv(strValue.c_str());

						if(verboseEnabled) printf("Trying [%s]\n",getenv("VLC_PLUGIN_PATH"));
						libvlc = libvlc_new(vlc_argc, &vlc_argv[0]);
					}

					if(libvlc == NULL) {
						_putenv("VLC_PLUGIN_PATH=c:\\program files\\videolan\\vlc\\plugins");

						if(verboseEnabled) printf("Trying [%s]\n",getenv("VLC_PLUGIN_PATH"));
						libvlc = libvlc_new(vlc_argc, &vlc_argv[0]);
					}
					if(libvlc == NULL) {
						_putenv("VLC_PLUGIN_PATH=\\program files\\videolan\\vlc\\plugins");

						if(verboseEnabled) printf("Trying [%s]\n",getenv("VLC_PLUGIN_PATH"));
						libvlc = libvlc_new(vlc_argc, &vlc_argv[0]);
					}
					if(libvlc == NULL) {
						_putenv("VLC_PLUGIN_PATH=c:\\program files (x86)\\videolan\\vlc\\plugins");

						if(verboseEnabled) printf("Trying [%s]\n",getenv("VLC_PLUGIN_PATH"));
						libvlc = libvlc_new(vlc_argc, &vlc_argv[0]);
					}
					if(libvlc == NULL) {
						_putenv("VLC_PLUGIN_PATH=\\program files (x86)\\videolan\\vlc\\plugins");

						if(verboseEnabled) printf("Trying [%s]\n",getenv("VLC_PLUGIN_PATH"));
						libvlc = libvlc_new(vlc_argc, &vlc_argv[0]);
					}
				}
			#endif
			*/

			if (ctxPtr->libvlc != NULL) {
#if defined(LIBVLC_VERSION_PRE_2) && defined(LIBVLC_VERSION_PRE_1_1_0)
				ctxPtr->m = libvlc_media_new(ctxPtr->libvlc, mediaURL.c_str(), &ex);
				if (verboseEnabled) printf("In [%s] Line: %d, m [%p]\n", __FUNCTION__, __LINE__, ctxPtr->m);

				catchError(&ex);
				ctxPtr->mp = libvlc_media_player_new_from_media(ctxPtr->m);
				if (verboseEnabled) printf("In [%s] Line: %d, mp [%p]\n", __FUNCTION__, __LINE__, ctxPtr->mp);

				libvlc_media_release(ctxPtr->m);
#else
				if (mediaURL.find(HTTP_PREFIX) == 0) {
					ctxPtr->mlp = libvlc_media_list_player_new(ctxPtr->libvlc);
					ctxPtr->ml = libvlc_media_list_new(ctxPtr->libvlc);
					ctxPtr->m = libvlc_media_new_location(ctxPtr->libvlc, mediaURL.c_str());

					libvlc_media_list_add_media(ctxPtr->ml, ctxPtr->m);
				} else {
					ctxPtr->m = libvlc_media_new_path(ctxPtr->libvlc, mediaURL.c_str());
				}

				/* Create a new item */
				if (verboseEnabled) printf("In [%s] Line: %d, m [%p]\n", __FUNCTION__, __LINE__, ctxPtr->m);

				if (loop == true) {
					libvlc_media_add_option(ctxPtr->m, "input-repeat=-1");
				}

				if (mediaURL.find(HTTP_PREFIX) == 0) {
					ctxPtr->mp = libvlc_media_player_new(ctxPtr->libvlc);
				} else {
					ctxPtr->mp = libvlc_media_player_new_from_media(ctxPtr->m);
				}
				if (verboseEnabled) printf("In [%s] Line: %d, mp [%p]\n", __FUNCTION__, __LINE__, ctxPtr->mp);

				libvlc_media_player_set_media(ctxPtr->mp, ctxPtr->m);

				libvlc_media_release(ctxPtr->m);

				if (mediaURL.find(HTTP_PREFIX) == 0) {
					// Use our media list
					libvlc_media_list_player_set_media_list(ctxPtr->mlp, ctxPtr->ml);

					// Use a given media player
					libvlc_media_list_player_set_media_player(ctxPtr->mlp, ctxPtr->mp);
				}

				// Get an event manager for the media player.
				if (mediaURL.find(HTTP_PREFIX) == 0) {
					libvlc_event_manager_t *eventManager = libvlc_media_list_player_event_manager(ctxPtr->mlp);

					if (eventManager) {
						//				libvlc_event_attach(eventManager, libvlc_MediaPlayerPlaying, (libvlc_callback_t)trapPlayingEvent, NULL, &ex);
						//				libvlc_event_attach(eventManager, libvlc_MediaPlayerEndReached, (libvlc_callback_t)trapEndReachedEvent, NULL, &ex);
						//				libvlc_event_attach(eventManager, libvlc_MediaPlayerBuffering, (libvlc_callback_t)trapBufferingEvent, NULL, &ex);
						//				libvlc_event_attach(eventManager, libvlc_MediaPlayerEncounteredError, (libvlc_callback_t)trapErrorEvent, NULL, &ex);

						int event_added = libvlc_event_attach(eventManager, libvlc_MediaListPlayerNextItemSet, callbacks, ctxPtr);
						if (event_added != 0) {
							printf("ERROR CANNOT ADD EVENT [libvlc_MediaListPlayerNextItemSet]\n");
						}
					}
				}
				//else {
					//libvlc_event_manager_t *eventManager = libvlc_media_player_event_manager(mp, &ex);
				libvlc_event_manager_t *eventManager = libvlc_media_player_event_manager(ctxPtr->mp);
				if (eventManager) {
					int event_added = libvlc_event_attach(eventManager, libvlc_MediaPlayerSnapshotTaken, callbacks, ctxPtr);
					if (event_added != 0) {
						printf("ERROR CANNOT ADD EVENT [libvlc_MediaPlayerSnapshotTaken]\n");
					}
					//				event_added = libvlc_event_attach( eventManager, libvlc_MediaPlayerTimeChanged,     callbacks, ctxPtr );
					//				if(event_added != 0) {
					//					printf("ERROR CANNOT ADD EVENT [libvlc_MediaPlayerTimeChanged]\n");
					//				}

					event_added = libvlc_event_attach(eventManager, libvlc_MediaPlayerPlaying, callbacks, ctxPtr);
					if (event_added != 0) {
						printf("ERROR CANNOT ADD EVENT [libvlc_MediaPlayerPlaying]\n");
					}

					event_added = libvlc_event_attach(eventManager, libvlc_MediaPlayerPaused, callbacks, ctxPtr);
					if (event_added != 0) {
						printf("ERROR CANNOT ADD EVENT [libvlc_MediaPlayerPaused]\n");
					}

					event_added = libvlc_event_attach(eventManager, libvlc_MediaPlayerStopped, callbacks, ctxPtr);
					if (event_added != 0) {
						printf("ERROR CANNOT ADD EVENT [libvlc_MediaPlayerStopped]\n");
					}

					event_added = libvlc_event_attach(eventManager, libvlc_MediaPlayerEndReached, callbacks, ctxPtr);
					if (event_added != 0) {
						printf("ERROR CANNOT ADD EVENT [libvlc_MediaPlayerEndReached]\n");
					}

					event_added = libvlc_event_attach(eventManager, libvlc_MediaPlayerPositionChanged, callbacks, ctxPtr);
					if (event_added != 0) {
						printf("ERROR CANNOT ADD EVENT [libvlc_MediaPlayerPositionChanged]\n");
					}

					event_added = libvlc_event_attach(eventManager, libvlc_MediaPlayerLengthChanged, callbacks, ctxPtr);
					if (event_added != 0) {
						printf("ERROR CANNOT ADD EVENT [libvlc_MediaPlayerLengthChanged]\n");
					}

					event_added = libvlc_event_attach(eventManager, libvlc_MediaPlayerEncounteredError, callbacks, ctxPtr);
					if (event_added != 0) {
						printf("ERROR CANNOT ADD EVENT [libvlc_MediaPlayerEncounteredError]\n");
					}

					event_added = libvlc_event_attach(eventManager, libvlc_MediaPlayerPausableChanged, callbacks, ctxPtr);
					if (event_added != 0) {
						printf("ERROR CANNOT ADD EVENT [libvlc_MediaPlayerPausableChanged]\n");
					}

					event_added = libvlc_event_attach(eventManager, libvlc_MediaPlayerSeekableChanged, callbacks, ctxPtr);
					if (event_added != 0) {
						printf("ERROR CANNOT ADD EVENT [libvlc_MediaPlayerSeekableChanged]\n");
					}

					//				event_added = libvlc_event_attach( eventManager, libvlc_MediaStateChanged, callbacks, ctxPtr );
					//				if(event_added != 0) {
					//					printf("ERROR CANNOT ADD EVENT [libvlc_MediaStateChanged]\n");
					//				}

					//				event_added = libvlc_event_attach( eventManager, libvlc_MediaParsedChanged, callbacks, ctxPtr );
					//				if(event_added != 0) {
					//					printf("ERROR CANNOT ADD EVENT [libvlc_MediaParsedChanged]\n");
					//				}

#if defined(LIBVLC_VERSION_PRE_2) && defined(LIBVLC_VERSION_PRE_1_1_0)
					event_added = libvlc_event_attach(eventManager, libvlc_MediaPlayerVout, callbacks, ctxPtr);
					if (event_added != 0) {
						printf("ERROR CANNOT ADD EVENT [libvlc_MediaPlayerVout]\n");
					}
#endif

					//				event_added = libvlc_event_attach( eventManager, libvlc_MediaListItemAdded, callbacks, ctxPtr );
					//				if(event_added != 0) {
					//					printf("ERROR CANNOT ADD EVENT [libvlc_MediaListItemAdded]\n");
					//				}
					//
					//				event_added = libvlc_event_attach( eventManager, libvlc_MediaListWillAddItem, callbacks, ctxPtr );
					//				if(event_added != 0) {
					//					printf("ERROR CANNOT ADD EVENT [libvlc_MediaListWillAddItem]\n");
					//				}
					//
					//				event_added = libvlc_event_attach( eventManager, libvlc_MediaListItemDeleted, callbacks, ctxPtr );
					//				if(event_added != 0) {
					//					printf("ERROR CANNOT ADD EVENT [libvlc_MediaListItemDeleted]\n");
					//				}
					//
					//				event_added = libvlc_event_attach( eventManager, libvlc_MediaListWillDeleteItem, callbacks, ctxPtr );
					//				if(event_added != 0) {
					//					printf("ERROR CANNOT ADD EVENT [libvlc_MediaListWillDeleteItem]\n");
					//				}
					//
					//				event_added = libvlc_event_attach( eventManager, libvlc_MediaListViewItemAdded, callbacks, ctxPtr );
					//				if(event_added != 0) {
					//					printf("ERROR CANNOT ADD EVENT [libvlc_MediaListViewItemAdded]\n");
					//				}
					//
					//				event_added = libvlc_event_attach( eventManager, libvlc_MediaListViewWillAddItem, callbacks, ctxPtr );
					//				if(event_added != 0) {
					//					printf("ERROR CANNOT ADD EVENT [libvlc_MediaListViewWillAddItem]\n");
					//				}
					//
					//				event_added = libvlc_event_attach( eventManager, libvlc_MediaListViewItemDeleted, callbacks, ctxPtr );
					//				if(event_added != 0) {
					//					printf("ERROR CANNOT ADD EVENT [libvlc_MediaListViewItemDeleted]\n");
					//				}
					//
					//				event_added = libvlc_event_attach( eventManager, libvlc_MediaListViewWillDeleteItem, callbacks, ctxPtr );
					//				if(event_added != 0) {
					//					printf("ERROR CANNOT ADD EVENT [libvlc_MediaListViewWillDeleteItem]\n");
					//				}
					//
					//				event_added = libvlc_event_attach( eventManager, libvlc_MediaListPlayerPlayed, callbacks, ctxPtr );
					//				if(event_added != 0) {
					//					printf("ERROR CANNOT ADD EVENT [libvlc_MediaListPlayerPlayed]\n");
					//				}
					//
					//				event_added = libvlc_event_attach( eventManager, libvlc_MediaListPlayerNextItemSet, callbacks, ctxPtr );
					//				if(event_added != 0) {
					//					printf("ERROR CANNOT ADD EVENT [libvlc_MediaListPlayerNextItemSet]\n");
					//				}
					//
					//				event_added = libvlc_event_attach( eventManager, libvlc_MediaListPlayerStopped, callbacks, ctxPtr );
					//				if(event_added != 0) {
					//					printf("ERROR CANNOT ADD EVENT [libvlc_MediaListPlayerStopped]\n");
					//				}
					//
					//				event_added = libvlc_event_attach( eventManager, libvlc_MediaDiscovererStarted, callbacks, ctxPtr );
					//				if(event_added != 0) {
					//					printf("ERROR CANNOT ADD EVENT [libvlc_MediaDiscovererStarted]\n");
					//				}
					//
					//				event_added = libvlc_event_attach( eventManager, libvlc_MediaDiscovererEnded, callbacks, ctxPtr );
					//				if(event_added != 0) {
					//					printf("ERROR CANNOT ADD EVENT [libvlc_MediaDiscovererEnded]\n");
					//				}
					//
					//				event_added = libvlc_event_attach( eventManager, libvlc_VlmMediaAdded, callbacks, ctxPtr );
					//				if(event_added != 0) {
					//					printf("ERROR CANNOT ADD EVENT [libvlc_VlmMediaAdded]\n");
					//				}
					//
					//				event_added = libvlc_event_attach( eventManager, libvlc_VlmMediaRemoved, callbacks, ctxPtr );
					//				if(event_added != 0) {
					//					printf("ERROR CANNOT ADD EVENT [libvlc_VlmMediaRemoved]\n");
					//				}
					//
					//				event_added = libvlc_event_attach( eventManager, libvlc_VlmMediaChanged, callbacks, ctxPtr );
					//				if(event_added != 0) {
					//					printf("ERROR CANNOT ADD EVENT [libvlc_VlmMediaChanged]\n");
					//				}
					//
					//				event_added = libvlc_event_attach( eventManager, libvlc_VlmMediaInstanceStarted, callbacks, ctxPtr );
					//				if(event_added != 0) {
					//					printf("ERROR CANNOT ADD EVENT [libvlc_VlmMediaInstanceStarted]\n");
					//				}
					//
					//				event_added = libvlc_event_attach( eventManager, libvlc_VlmMediaInstanceStopped, callbacks, ctxPtr );
					//				if(event_added != 0) {
					//					printf("ERROR CANNOT ADD EVENT [libvlc_VlmMediaInstanceStopped]\n");
					//				}
					//
					//				event_added = libvlc_event_attach( eventManager, libvlc_VlmMediaInstanceStatusInit, callbacks, ctxPtr );
					//				if(event_added != 0) {
					//					printf("ERROR CANNOT ADD EVENT [libvlc_VlmMediaInstanceStatusInit]\n");
					//				}
					//
					//				event_added = libvlc_event_attach( eventManager, libvlc_VlmMediaInstanceStatusOpening, callbacks, ctxPtr );
					//				if(event_added != 0) {
					//					printf("ERROR CANNOT ADD EVENT [libvlc_VlmMediaInstanceStatusOpening]\n");
					//				}
					//
					//				event_added = libvlc_event_attach( eventManager, libvlc_VlmMediaInstanceStatusPlaying, callbacks, ctxPtr );
					//				if(event_added != 0) {
					//					printf("ERROR CANNOT ADD EVENT [libvlc_VlmMediaInstanceStatusPlaying]\n");
					//				}
					//
					//				event_added = libvlc_event_attach( eventManager, libvlc_VlmMediaInstanceStatusPause, callbacks, ctxPtr );
					//				if(event_added != 0) {
					//					printf("ERROR CANNOT ADD EVENT [libvlc_VlmMediaInstanceStatusPause]\n");
					//				}
					//
					//				event_added = libvlc_event_attach( eventManager, libvlc_VlmMediaInstanceStatusEnd, callbacks, ctxPtr );
					//				if(event_added != 0) {
					//					printf("ERROR CANNOT ADD EVENT [libvlc_VlmMediaInstanceStatusEnd]\n");
					//				}
					//
					//				event_added = libvlc_event_attach( eventManager, libvlc_VlmMediaInstanceStatusError, callbacks, ctxPtr );
					//				if(event_added != 0) {
					//					printf("ERROR CANNOT ADD EVENT [libvlc_VlmMediaInstanceStatusError]\n");
					//				}

				}
				//}

				//libvlc_media_release(ctxPtr->m);
#endif


#if !defined(LIBVLC_VERSION_PRE_2) && !defined(LIBVLC_VERSION_PRE_1_1_0)
				libvlc_video_set_callbacks(ctxPtr->mp, lock, unlock, display, ctxPtr);
				libvlc_video_set_format(ctxPtr->mp, "RV16", width, height, SDL_GetWindowSurface(this->window)->pitch);

#endif

				ctxPtr->isPlaying = true;

#if defined(LIBVLC_VERSION_PRE_2) && defined(LIBVLC_VERSION_PRE_1_1_0)
				int play_result = libvlc_media_player_play(ctxPtr->mp, &ex);
#else
				int play_result = 0;
				if (mediaURL.find(HTTP_PREFIX) == 0) {
					libvlc_media_list_player_play(ctxPtr->mlp);
				} else {
					play_result = libvlc_media_player_play(ctxPtr->mp);
				}
				// Play
				//int play_result = 0;
				//libvlc_media_list_player_play(ctxPtr->mlp);
#endif

		//SDL_Delay(5);
				if (verboseEnabled) printf("In [%s] Line: %d, play_result [%d]\n", __FUNCTION__, __LINE__, play_result);

				successLoadingLib = (play_result == 0);

			}
#endif

			return successLoadingLib;
		}

		bool VideoPlayer::initPlayer() {
			if (VideoPlayer::disabled == true) {
				return true;
			}

#ifdef HAS_LIBVLC

			bool result = initPlayer(this->filename);
			if (result == true) {
				time_t waitStart = time(NULL);
				for (; difftime(time(NULL), waitStart) <= MAX_VIDEO_START_MILLISECONDS &&
					successLoadingLib == true &&
					(ctxPtr->error == false || ctxPtr->stopped == false) &&
					ctxPtr->started == false;) {
					if (ctxPtr->started == true) {
						break;
					}
					if (this->loadingCB != NULL) {
						int progress = (int) ((difftime(time(NULL), waitStart) / MAX_VIDEO_START_MILLISECONDS) * 100.0);
						this->loadingCB->renderVideoLoading(progress);
					}
					SDL_Delay(0);
				}
			}

			if (isPlaying() == false && this->filenameFallback != "") {
				closePlayer();
				cleanupPlayer();

				init();

				result = initPlayer(this->filenameFallback);
				if (result == true) {
					time_t waitStart = time(NULL);
					for (; difftime(time(NULL), waitStart) <= MAX_VIDEO_START_MILLISECONDS &&
						successLoadingLib == true &&
						(ctxPtr->error == false || ctxPtr->stopped == false) &&
						ctxPtr->started == false;) {
						if (ctxPtr->started == true) {
							break;
						}
						if (this->loadingCB != NULL) {
							int progress = (int) ((difftime(time(NULL), waitStart) / MAX_VIDEO_START_MILLISECONDS) * 100.0);
							this->loadingCB->renderVideoLoading(progress);
						}
						SDL_Delay(0);
					}
				}
			}

#endif

			return successLoadingLib;
		}

		void VideoPlayer::closePlayer() {
#ifdef HAS_LIBVLC
			if (ctxPtr != NULL && ctxPtr->libvlc != NULL) {
				//
				// Stop stream and clean up libVLC
				//
#if defined(LIBVLC_VERSION_PRE_2) && defined(LIBVLC_VERSION_PRE_1_1_0)
				libvlc_media_player_stop(ctxPtr->mp, &ex);
				catchError(&ex);
#else
				libvlc_media_player_stop(ctxPtr->mp);
#endif
				if (ctxPtr->mlp != NULL) {
					libvlc_media_list_player_release(ctxPtr->mlp);
					ctxPtr->mlp = NULL;
				}
				libvlc_media_player_release(ctxPtr->mp);
				ctxPtr->mp = NULL;
				libvlc_release(ctxPtr->libvlc);
			}
#endif

			//
			// Close window and clean up libSDL
			//
			if (ctxPtr != NULL) {
				if (ctxPtr->mutex != NULL) {
					SDL_DestroyMutex(ctxPtr->mutex);
				}
				if (ctxPtr->surf != NULL) {
					SDL_FreeSurface(ctxPtr->surf);
				}
				if (ctxPtr->empty != NULL) {
					SDL_FreeSurface(ctxPtr->empty);
				}

				glDeleteTextures(1, &ctxPtr->textureId);

				if (ctxPtr->needToQuit == true) {
					SDL_Event quit_event = { SDL_QUIT };
					SDL_PushEvent(&quit_event);
				}
			}
		}

		void VideoPlayer::PlayVideo() {
			if (VideoPlayer::disabled == true) {
				return;
			}

			/*
			#ifdef HAS_LIBVLC
				libvlc_instance_t *libvlc = NULL;
				libvlc_media_t *m = NULL;
				libvlc_media_player_t *mp = NULL;

			//	string pluginParam = "";
			//	if(pluginsPath != "") {
			//		pluginParam = "--plugin-path=" + pluginsPath;
			//	}

				std::vector<const char *> vlc_argv;
				vlc_argv.push_back("--intf=dummy");
				vlc_argv.push_back("--no-media-library");
				vlc_argv.push_back("--ignore-config"); // Don't use VLC's config
				vlc_argv.push_back("--no-xlib"); // tell VLC to not use Xlib
				vlc_argv.push_back("--no-video-title-show");
			#if defined(LIBVLC_VERSION_PRE_2)
				string fullPluginsParam = "--plugin-path=" + pluginsPath;
				vlc_argv.push_back(fullPluginsParam.c_str());
			#endif

			#if defined(LIBVLC_VERSION_PRE_2) && defined(LIBVLC_VERSION_PRE_1_1_0)
				char clock[64], cunlock[64], cdata[64];
					char cwidth[32], cheight[32], cpitch[32];
				//
				//  Initialise libVLC
				//
				sprintf(clock, "%lld", (long long int)(intptr_t)lock);
				sprintf(cunlock, "%lld", (long long int)(intptr_t)unlock);
				sprintf(cdata, "%lld", (long long int)(intptr_t)ctxPtr);
				sprintf(cwidth, "%i", width);
				sprintf(cheight, "%i", height);
				sprintf(cpitch, "%i", colorBits);

				vlc_argv.push_back("--vout");
				vlc_argv.push_back("vmem");
				vlc_argv.push_back("--vmem-width");
				vlc_argv.push_back(cwidth);
					vlc_argv.push_back("--vmem-height");
				vlc_argv.push_back(cheight);
					vlc_argv.push_back("--vmem-pitch");
				vlc_argv.push_back(cpitch);
					vlc_argv.push_back("--vmem-chroma");
				vlc_argv.push_back("RV16");
					vlc_argv.push_back("--vmem-lock");
				vlc_argv.push_back(clock);
					vlc_argv.push_back("--vmem-unlock");
				vlc_argv.push_back(cunlock);
					vlc_argv.push_back("--vmem-data");
				vlc_argv.push_back(cdata);

			#endif

				if(verboseEnabled) vlc_argv.push_back("--verbose=2");
				if(verboseEnabled) vlc_argv.push_back("--extraintf=logger"); //log anything
			#if defined(WIN32)
				if(verboseEnabled) _putenv("VLC_VERBOSE=2");
			#endif
				int vlc_argc = vlc_argv.size();

			//	char const *vlc_argv[] =
			//	{
			//		//"--no-audio", // skip any audio track
			//		"--no-xlib", // tell VLC to not use Xlib
			//		"--no-video-title-show",
			//		pluginParam.c_str(),
			//	};
			//	int vlc_argc = sizeof(vlc_argv) / sizeof(*vlc_argv);
			#endif

				SDL_Surface *empty = NULL;
				glEnable(GL_TEXTURE_2D);
				glEnable(GL_DEPTH_TEST);
				// Init Texture
				glGenTextures(1, &ctxPtr->textureId);
				glBindTexture(GL_TEXTURE_2D, ctxPtr->textureId);
				glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
				glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

				empty = SDL_CreateRGBSurface(SDL_SWSURFACE, width, height,
						colorBits, 0, 0, 0, 0);
				ctxPtr->surf = SDL_CreateRGBSurface(SDL_SWSURFACE, width, height,
						colorBits, 0x001f, 0x07e0, 0xf800, 0);
				ctxPtr->mutex = SDL_CreateMutex();

			#ifdef HAS_LIBVLC
				//
				//  Initialize libVLC
				//
				if(verboseEnabled) printf("Trying [%s]\n",getenv("VLC_PLUGIN_PATH"));

			#if defined(LIBVLC_VERSION_PRE_2) && defined(LIBVLC_VERSION_PRE_1_1_0)
				libvlc_exception_t ex;
				libvlc_exception_init(&ex);

				libvlc = libvlc_new(vlc_argc, &vlc_argv[0],&ex);
				catchError(&ex);
			#else
				libvlc = libvlc_new(vlc_argc, &vlc_argv[0]);
			#endif

				if(verboseEnabled) printf("In [%s] Line: %d, libvlc [%p]\n",__FUNCTION__,__LINE__,libvlc);

			// It is meaningless to try all this because we have to restart the game to pickup new env vars
			#if defined(WIN32)
				if(libvlc == NULL) {
					// For windows check registry for install path
					std::string strValue = getRegKey("Software\\VideoLAN\\VLC", "InstallDir");
					if(strValue != "") {
						if(strValue.length() >= 2) {
							if(strValue[0] == '"') {
								strValue = strValue.erase(0);
							}
							if(strValue[strValue.length()-1] == '"') {
								strValue = strValue.erase(strValue.length()-1);
							}
						}
						strValue = "VLC_PLUGIN_PATH=" + strValue;
						_putenv(strValue.c_str());

						if(verboseEnabled) printf("Trying [%s]\n",getenv("VLC_PLUGIN_PATH"));
						libvlc = libvlc_new(vlc_argc, &vlc_argv[0]);
					}

					if(libvlc == NULL) {
						_putenv("VLC_PLUGIN_PATH=c:\\program files\\videolan\\vlc\\plugins");

						if(verboseEnabled) printf("Trying [%s]\n",getenv("VLC_PLUGIN_PATH"));
						libvlc = libvlc_new(vlc_argc, &vlc_argv[0]);
					}
					if(libvlc == NULL) {
						_putenv("VLC_PLUGIN_PATH=\\program files\\videolan\\vlc\\plugins");

						if(verboseEnabled) printf("Trying [%s]\n",getenv("VLC_PLUGIN_PATH"));
						libvlc = libvlc_new(vlc_argc, &vlc_argv[0]);
					}
					if(libvlc == NULL) {
						_putenv("VLC_PLUGIN_PATH=c:\\program files (x86)\\videolan\\vlc\\plugins");

						if(verboseEnabled) printf("Trying [%s]\n",getenv("VLC_PLUGIN_PATH"));
						libvlc = libvlc_new(vlc_argc, &vlc_argv[0]);
					}
					if(libvlc == NULL) {
						_putenv("VLC_PLUGIN_PATH=\\program files (x86)\\videolan\\vlc\\plugins");

						if(verboseEnabled) printf("Trying [%s]\n",getenv("VLC_PLUGIN_PATH"));
						libvlc = libvlc_new(vlc_argc, &vlc_argv[0]);
					}
				}
			#endif
			//

				if(libvlc != NULL) {
			#if defined(LIBVLC_VERSION_PRE_2) && defined(LIBVLC_VERSION_PRE_1_1_0)
					m = libvlc_media_new(libvlc, filename.c_str(), &ex);
					if(verboseEnabled) printf("In [%s] Line: %d, m [%p]\n",__FUNCTION__,__LINE__,m);

					catchError(&ex);
					mp = libvlc_media_player_new_from_media(m);
					if(verboseEnabled) printf("In [%s] Line: %d, mp [%p]\n",__FUNCTION__,__LINE__,mp);
			#else
					// Create a new item
					m = libvlc_media_new_path(libvlc, filename.c_str());
					if(verboseEnabled) printf("In [%s] Line: %d, m [%p]\n",__FUNCTION__,__LINE__,m);

					mp = libvlc_media_player_new_from_media(m);
					if(verboseEnabled) printf("In [%s] Line: %d, mp [%p]\n",__FUNCTION__,__LINE__,mp);
			#endif
					libvlc_media_release(m);

			#if !defined(LIBVLC_VERSION_PRE_2) && !defined(LIBVLC_VERSION_PRE_1_1_0)
					libvlc_video_set_callbacks(mp, lock, unlock, display, ctxPtr);
					libvlc_video_set_format(mp, "RV16", width, height, this->window->pitch);

					// Get an event manager for the media player.
					//libvlc_event_manager_t *eventManager = libvlc_media_player_event_manager(mp, &ex);
					libvlc_event_manager_t *eventManager = libvlc_media_player_event_manager(mp);
					if(eventManager) {
			//			libvlc_event_attach(eventManager, libvlc_MediaPlayerPlaying, (libvlc_callback_t)trapPlayingEvent, NULL, &ex);
			//			libvlc_event_attach(eventManager, libvlc_MediaPlayerEndReached, (libvlc_callback_t)trapEndReachedEvent, NULL, &ex);
			//			libvlc_event_attach(eventManager, libvlc_MediaPlayerBuffering, (libvlc_callback_t)trapBufferingEvent, NULL, &ex);
			//			libvlc_event_attach(eventManager, libvlc_MediaPlayerEncounteredError, (libvlc_callback_t)trapErrorEvent, NULL, &ex);
						libvlc_event_attach(eventManager, libvlc_MediaPlayerPlaying, (libvlc_callback_t)trapPlayingEvent, ctxPtr);
						libvlc_event_attach(eventManager, libvlc_MediaPlayerEndReached, (libvlc_callback_t)trapEndReachedEvent, ctxPtr);
						libvlc_event_attach(eventManager, libvlc_MediaPlayerBuffering, (libvlc_callback_t)trapBufferingEvent, ctxPtr);
						libvlc_event_attach(eventManager, libvlc_MediaPlayerEncounteredError, (libvlc_callback_t)trapErrorEvent, ctxPtr);
					}
			#endif

					ctxPtr->isPlaying = true;
			#if defined(LIBVLC_VERSION_PRE_2) && defined(LIBVLC_VERSION_PRE_1_1_0)
					int play_result = libvlc_media_player_play(mp,&ex);
			#else
					int play_result = libvlc_media_player_play(mp);
			#endif

					//SDL_Delay(5);
					if(verboseEnabled) printf("In [%s] Line: %d, play_result [%d]\n",__FUNCTION__,__LINE__,play_result);

					successLoadingLib = (play_result == 0);
				}
			#endif

				//
				 /  Main loop
				 //
				//int done = 0, action = 0, pause = 0, n = 0;
				bool needToQuit = false;
				while(isPlaying() == true) {
					needToQuit = playFrame();
				}

			#ifdef HAS_LIBVLC
				if(libvlc != NULL) {
					//
					 / Stop stream and clean up libVLC
					 //
			#if defined(LIBVLC_VERSION_PRE_2) && defined(LIBVLC_VERSION_PRE_1_1_0)
					libvlc_media_player_stop(mp,&ex);
					catchError(&ex);
			#else
					libvlc_media_player_stop(mp);
			#endif
					libvlc_media_player_release(mp);
					libvlc_release(libvlc);
				}
			#endif

				//
				 / Close window and clean up libSDL
				 //
				SDL_DestroyMutex(ctxPtr->mutex);
				SDL_FreeSurface(ctxPtr->surf);
				SDL_FreeSurface(empty);

				glDeleteTextures(1, &ctxPtr->textureId);

				if(needToQuit == true) {
					SDL_Event quit_event = {SDL_QUIT};
					SDL_PushEvent(&quit_event);
				}
			*/

			initPlayer();
			for (; isPlaying() == true;) {
				playFrame();
			}
			closePlayer();
		}

		bool VideoPlayer::isPlaying() const {
			bool result = (successLoadingLib == true &&
				ctxPtr != NULL && ctxPtr->isPlaying == true &&
				//ctxPtr->error == false &&
				(ctxPtr->error == false || ctxPtr->stopped == false) &&
				finished == false && stop == false);

			if (ctxPtr != NULL && ctxPtr->verboseEnabled) printf("isPlaying isPlaying = %d,error = %d, stopped = %d, end_of_media = %d\n", ctxPtr->isPlaying, ctxPtr->error, ctxPtr->stopped, ctxPtr->end_of_media);
			return result;
		}

		bool VideoPlayer::playFrame(bool swapBuffers) {
			if (VideoPlayer::disabled == true) {
				return false;
			}

			if (successLoadingLib == true &&
				ctxPtr != NULL && ctxPtr->isPlaying == true &&
				finished == false && stop == false) {

				//int action = 0, pause = 0, n = 0;
				//int action = 0, n = 0;
				int action = 0;

				SDL_Event event;
				/* Keys: enter (fullscreen), space (pause), escape (quit) */
				//while( SDL_PollEvent( &event ) ) {
				if (SDL_PollEvent(&event)) {
					switch (event.type) {
						case SDL_QUIT:
							finished = true;
							ctxPtr->needToQuit = true;
							break;
						case SDL_KEYDOWN:
							action = event.key.keysym.sym;
							break;
						case SDL_MOUSEBUTTONDOWN:
							finished = true;
							break;
					}
				}

				if (finished == false && stop == false) {
					switch (action) {
						case SDLK_ESCAPE:
							finished = true;
							break;
						case SDLK_RETURN:
							//options ^= SDL_WINDOW_FULLSCREEN;
							//screen = SDL_SetVideoMode(WIDTH, HEIGHT, 0, options);
							finished = true;
							break;
							//case ' ':
							//	//pause = !pause;
							//	break;
					}

					//if(pause == 0) {
					//n++;
					//}

					//assertGl();

					glPushAttrib(GL_ENABLE_BIT);

					//glDisable(GL_LIGHTING);
					glEnable(GL_TEXTURE_2D);
					glEnable(GL_BLEND);

					// Loading the texture
					loadTexture(ctxPtr);

					if (ctxPtr->x == -1 || ctxPtr->y == -1) {
						glBegin(GL_QUADS);
						glTexCoord2d(0, 1);
						glVertex2f(-0.85f, 0.85f);
						glTexCoord2d(1, 1);
						glVertex2f(0.85f, 0.85f);
						glTexCoord2d(1, 0);
						glVertex2f(0.85f, -0.85f);
						glTexCoord2d(0, 0);
						glVertex2f(-0.85f, -0.85f);
						glEnd();
					} else {
						const double HEIGHT_DEFAULT = 768;
						const double WIDTH_DEFAULT = 1024;

						const double HEIGHT_MULTIPLIER = HEIGHT_DEFAULT / (double) ctxPtr->height;
						const double WIDTH_MULTIPLIER = WIDTH_DEFAULT / (double) ctxPtr->width;

						//printf("w x h = %d x %d\n",ctxPtr->width,ctxPtr->height);

						glBegin(GL_TRIANGLE_STRIP);
						glTexCoord2i(0, 1);
						glVertex2i(ctxPtr->x, (int) ((double) ctxPtr->y + (double) ctxPtr->height * HEIGHT_MULTIPLIER));
						glTexCoord2i(0, 0);
						glVertex2i(ctxPtr->x, ctxPtr->y);
						glTexCoord2i(1, 1);
						glVertex2i((int) ((double) ctxPtr->x + (double) ctxPtr->width * WIDTH_MULTIPLIER), (int) ((double) ctxPtr->y + (double) ctxPtr->height * HEIGHT_MULTIPLIER));
						glTexCoord2i(1, 0);
						glVertex2i((int) ((double) ctxPtr->x + (double) ctxPtr->width * WIDTH_MULTIPLIER), ctxPtr->y);
						glEnd();

					}

					glPopAttrib();

					if (swapBuffers == true) {
						SDL_GL_SwapWindow(window);
					}
				}
			}

			if (ctxPtr != NULL) {
				return ctxPtr->needToQuit;
			} else {
				return false;
			}
		}

		void VideoPlayer::RestartVideo() {
			//printf("Restart video\n");

			//this->stop = false;
			//this->finished = false;
			//ctxPtr->started = true;
			//ctxPtr->error = false;
			//ctxPtr->stopped = false;
			//ctxPtr->end_of_media = false;
			//ctxPtr->isPlaying = true;
			//ctxPtr->needToQuit = false;

			//return;

			this->closePlayer();

			this->stop = false;
			this->finished = false;
			this->successLoadingLib = false;

			this->initPlayer();
		}

	}
}
