#include "stdafx.h"
#include "CLS_CudaCoreApi.h"
#include "RetValue.h"

CLS_CudaDecApi* CLS_CudaDecApi::m_pclsInstance = NULL;

#define CUDACORE_CHECK_NULL_RETURN(A) if (NULL == A){return FALSE;}

#ifdef  __WIN__
#define RTLD_LAZY 0
static HMODULE InnerLoadLibrary(const char* _pcCurrentModuleName, const char* _pcDllName, HMODULE _hModuleSrc /*= NULL*/)
{
	char fileName[MAX_PATH];
	char fileNameLower[MAX_PATH];
	char curModNameLower[MAX_PATH];

	memset(fileName, 0, MAX_PATH);
	memset(fileNameLower, 0, MAX_PATH);
	memset(curModNameLower, 0, MAX_PATH);

	HMODULE hMod = (NULL == _hModuleSrc ? GetModuleHandle(_pcCurrentModuleName) : _hModuleSrc);
	GetModuleFileName(hMod, fileName, MAX_PATH);

	strcpy_s(fileNameLower, sizeof(fileNameLower), fileName);
	strcpy_s(curModNameLower, sizeof(curModNameLower), _pcCurrentModuleName);

	char* pcPos = NULL;
	if (NULL != _hModuleSrc)
	{
		pcPos = strrchr(fileNameLower, '\\');//查找最后一个'\\'
		pcPos++;
	}
	else
	{
		pcPos = strstr(fileNameLower, curModNameLower);
	}

	HMODULE hHandle = NULL;
	if (NULL != pcPos)
	{
		memset(pcPos, 0, MAX_PATH - (pcPos - fileNameLower));//将fileName中pos之后的字符抹去，避免出现_pDllName短于_pCurrentModuleName的情况。
		strcpy_s(pcPos, MAX_PATH - (pcPos - fileNameLower) - 1, _pcDllName);

		hHandle = LoadLibrary(fileNameLower);
	}
	else
	{
		hHandle = LoadLibrary(_pcDllName);
	}

	return hHandle;		
}

static void* dlopen(const char* _pcFileName, int _iFlag)
{
	return InnerLoadLibrary("" ,_pcFileName, NULL);
}

static void* dlsym(void* _pvHandle, const char* _pcSymbol)
{
	return GetProcAddress((HMODULE)_pvHandle, _pcSymbol);
}

static int dlclose(void* _pvHandle)
{
	if(FreeLibrary((HMODULE)_pvHandle))
	{
		return RET_SUCCESS;
	}

	return RET_FAILED;
}
#endif

CLS_CudaDecApi::CLS_CudaDecApi()
{
	m_pvCudaCoreHandle = NULL;
	m_pCudaCoreStartup = NULL;
	m_pCudaCoreCleanup = NULL;
	m_pCudaCoreGetGpuCount = NULL;
	m_pCudaCoreContextAlloc = NULL;
	m_pCudaCoreContextFree = NULL;
	m_pCudaCoreDecodeCreate = NULL;
	m_pCudaCoreDecodeFrame = NULL;
	m_pCudaCoreDecodeDestroy = NULL;
	m_pCudaCoreRegistResource = NULL;
	m_pCudaCoreUnRegistResource = NULL;
	m_pCudaCoreDecodeCopytoResouce = NULL;
	m_pCudaCoreDecodeGetFrame = NULL;
	m_pCudaCoreDecodeReleaseFrame = NULL;
	m_pCudaCoreGetAdapter = NULL;
}

CLS_CudaDecApi::~CLS_CudaDecApi()
{
	ReleaseLib();
}

CLS_CudaDecApi* CLS_CudaDecApi::Instance(void)
{
	if(NULL == m_pclsInstance)
	{
		m_pclsInstance = new CLS_CudaDecApi();	
	}

	return m_pclsInstance;
}

void CLS_CudaDecApi::Destroy()
{
	if (NULL != m_pclsInstance)
	{
		delete m_pclsInstance;
		m_pclsInstance = NULL;
	}
}

int CLS_CudaDecApi::CudaCoreStartup()
{
	CUDACORE_CHECK_NULL_RETURN(m_pCudaCoreStartup);
	return m_pCudaCoreStartup();
}

int CLS_CudaDecApi::CudaCoreCleanup()
{
	CUDACORE_CHECK_NULL_RETURN(m_pCudaCoreCleanup);
	return m_pCudaCoreCleanup();
}

int CLS_CudaDecApi::CudaCoreGetGpuCount()
{
	CUDACORE_CHECK_NULL_RETURN(m_pCudaCoreGetGpuCount);
	return m_pCudaCoreGetGpuCount();
}

CudaCoreContext CLS_CudaDecApi::CudaCoreContextAlloc(int _iGpuId)
{
	CUDACORE_CHECK_NULL_RETURN(m_pCudaCoreContextAlloc);
	return m_pCudaCoreContextAlloc(_iGpuId);
}

int CLS_CudaDecApi::CudaCoreContextFree(CudaCoreContext _pCtx)
{
	CUDACORE_CHECK_NULL_RETURN(m_pCudaCoreContextFree);
	return m_pCudaCoreContextFree(_pCtx);
}

int CLS_CudaDecApi::CudaCoreDecodeCreate(CudaCoreContext _pCtx, CudaDecodeParam* _pParam)
{
	CUDACORE_CHECK_NULL_RETURN(m_pCudaCoreDecodeCreate);
	return m_pCudaCoreDecodeCreate(_pCtx, _pParam);
}

int CLS_CudaDecApi::CudaCoreDecodeFrame(CudaCoreContext _pCtx, CudaDecodeIn* _pIn, CudaDecodeOut* _pOut)
{
	CUDACORE_CHECK_NULL_RETURN(m_pCudaCoreDecodeFrame);
	return m_pCudaCoreDecodeFrame(_pCtx, _pIn, _pOut);
}

int CLS_CudaDecApi::CudaCoreDecodeDestroy(CudaCoreContext _pCtx)
{
	CUDACORE_CHECK_NULL_RETURN(m_pCudaCoreDecodeDestroy);
	return m_pCudaCoreDecodeDestroy(_pCtx);
}

ResourceHandle CLS_CudaDecApi::CudaCoreRegistResource(CudaCoreContext _pCtx, void* _pvSurface)
{
	CUDACORE_CHECK_NULL_RETURN(m_pCudaCoreRegistResource);
	return m_pCudaCoreRegistResource(_pCtx, _pvSurface);
}

int CLS_CudaDecApi::CudaCoreUnRegistResource(CudaCoreContext _pCtx, ResourceHandle _pHandle)
{
	CUDACORE_CHECK_NULL_RETURN(m_pCudaCoreUnRegistResource);
	return m_pCudaCoreUnRegistResource(_pCtx, _pHandle);
}

int CLS_CudaDecApi::CudaCoreDecodeCopytoResouce(CudaCoreContext _pCtx, void* _pDevicePtr, ResourceHandle _pHandle)
{
	CUDACORE_CHECK_NULL_RETURN(m_pCudaCoreDecodeCopytoResouce);
	return m_pCudaCoreDecodeCopytoResouce(_pCtx, _pDevicePtr, _pHandle);
}

void* CLS_CudaDecApi::CudaCoreDecodeGetFrame(CudaCoreContext _pCtx, void* _pvDevicePtr)
{
	CUDACORE_CHECK_NULL_RETURN(m_pCudaCoreDecodeGetFrame);
	return m_pCudaCoreDecodeGetFrame(_pCtx, _pvDevicePtr);
}

int CLS_CudaDecApi::CudaCoreDecodeReleaseFrame(CudaCoreContext _pCtx, void* _pvDevicePtr)
{
	CUDACORE_CHECK_NULL_RETURN(m_pCudaCoreDecodeReleaseFrame);
	return m_pCudaCoreDecodeReleaseFrame(_pCtx, _pvDevicePtr);
}

int CLS_CudaDecApi::CudaCoreGetAdapter(CudaCoreContext _pCtx)
{
	CUDACORE_CHECK_NULL_RETURN(m_pCudaCoreGetAdapter);
	return m_pCudaCoreGetAdapter(_pCtx);
}

void* CLS_CudaDecApi::CudaCoreGetDeviceMem(CudaCoreContext _pCtx, void* _pvDevicePtr, int _iLen)
{
	CUDACORE_CHECK_NULL_RETURN(m_pCudaCoreGetDeviceMem);
	return m_pCudaCoreGetDeviceMem(_pCtx, _pvDevicePtr, _iLen);

}

int CLS_CudaDecApi::CudaCoreReleaseMem(CudaCoreContext _pCtx, void* _pvDevicePtr)
{
	CUDACORE_CHECK_NULL_RETURN(m_pCudaCoreReleaseMem);
	return m_pCudaCoreReleaseMem(_pCtx, _pvDevicePtr);
}

int CLS_CudaDecApi::CudaCoreMemcpy2D(CudaCoreContext _pCtx, CudaCoreMem2D* _ptM2D)
{
	CUDACORE_CHECK_NULL_RETURN(m_pCudaCoreMemcpy2D);
	return m_pCudaCoreMemcpy2D(_pCtx, _ptM2D);
}

int CLS_CudaDecApi::CudaCoreGetGpuID( CudaCoreContext _pCtx )
{
	CUDACORE_CHECK_NULL_RETURN(m_pCudaCoreGetGpuID);
	return m_pCudaCoreGetGpuID(_pCtx);
}



int	CLS_CudaDecApi::LoadLib()
{
#ifdef _USELIB
	m_pCudaCoreStartup = CudaCoreStartup;
	m_pCudaCoreCleanup = CudaCoreCleanup;
	m_pCudaCoreGetGpuCount = CudaCoreGetGpuCount;
	m_pCudaCoreContextAlloc = CudaCoreContextAlloc;
	m_pCudaCoreContextFree = CudaCoreContextFree;
	m_pCudaCoreDecodeCreate = CudaCoreDecodeCreate;
	m_pCudaCoreDecodeFrame = CudaCoreDecodeFrame;
	m_pCudaCoreDecodeDestroy = CudaCoreDecodeDestroy;
	m_pCudaCoreRegistResource = CudaCoreRegistResource;
	m_pCudaCoreUnRegistResource = CudaCoreUnRegistResource;
	m_pCudaCoreDecodeCopytoResouce = CudaCoreDecodeCopytoResouce;
	m_pCudaCoreDecodeGetFrame = CudaCoreDecodeGetFrame;
	m_pCudaCoreDecodeReleaseFrame = CudaCoreDecodeReleaseFrame;
	m_pCudaCoreGetAdapter = CudaCoreGetAdapter;
	m_pCudaCoreGetDeviceMem = CudaCoreGetDeviceMem;
	m_pCudaCoreReleaseMem = CudaCoreReleaseMem;
	m_pCudaCoreMemcpy2D = CudaCoreMemcpy2D;
	m_pCudaCoreGetGpuID = CudaCoreGetGpuID;

	return RET_SUCCESS;

#else

	if(NULL != m_pvCudaCoreHandle)
	{
		return RET_SUCCESS;
	}

	const char* pcCudaCoreName = NULL;
#ifdef __WIN__
	pcCudaCoreName = "CudaCore.dll";
#else
	pcCudaCoreName = "libcudacore.so";
#endif

	m_pvCudaCoreHandle = dlopen(pcCudaCoreName, RTLD_LAZY);
	if(NULL == m_pvCudaCoreHandle)
	{
// 		sdk_log_err_ex( "[CLS_CudaDecApi::LoadLib] load %s failed,errno=%d", pcCudaCoreName, errno);
		return RET_FAILED;
	}

	m_pCudaCoreStartup = (pCudaCoreStartup)dlsym(m_pvCudaCoreHandle, "CudaCoreStartup");
	m_pCudaCoreCleanup = (pCudaCoreCleanup)dlsym(m_pvCudaCoreHandle, "CudaCoreCleanup");
	m_pCudaCoreGetGpuCount = (pCudaCoreGetGpuCount)dlsym(m_pvCudaCoreHandle, "CudaCoreGetGpuCount");
	m_pCudaCoreContextAlloc = (pCudaCoreContextAlloc)dlsym(m_pvCudaCoreHandle, "CudaCoreContextAlloc");
	m_pCudaCoreContextFree = (pCudaCoreContextFree)dlsym(m_pvCudaCoreHandle, "CudaCoreContextFree");
	m_pCudaCoreDecodeCreate = (pCudaCoreDecodeCreate)dlsym(m_pvCudaCoreHandle, "CudaCoreDecodeCreate");
	m_pCudaCoreDecodeFrame = (pCudaCoreDecodeFrame)dlsym(m_pvCudaCoreHandle, "CudaCoreDecodeFrame");
	m_pCudaCoreDecodeDestroy = (pCudaCoreDecodeDestroy)dlsym(m_pvCudaCoreHandle, "CudaCoreDecodeDestroy");
	m_pCudaCoreRegistResource = (pCudaCoreRegistResource)dlsym(m_pvCudaCoreHandle, "CudaCoreRegistResource");
	m_pCudaCoreUnRegistResource = (pCudaCoreUnRegistResource)dlsym(m_pvCudaCoreHandle, "CudaCoreUnRegistResource");
	m_pCudaCoreDecodeCopytoResouce = (pCudaCoreDecodeCopytoResouce)dlsym(m_pvCudaCoreHandle, "CudaCoreDecodeCopytoResouce");
	m_pCudaCoreDecodeGetFrame = (pCudaCoreDecodeGetFrame)dlsym(m_pvCudaCoreHandle, "CudaCoreDecodeGetFrame");
	m_pCudaCoreDecodeReleaseFrame = (pCudaCoreDecodeReleaseFrame)dlsym(m_pvCudaCoreHandle, "CudaCoreDecodeReleaseFrame");
	m_pCudaCoreGetAdapter = (pCudaCoreGetAdapter)dlsym(m_pvCudaCoreHandle, "CudaCoreGetAdapter");
	m_pCudaCoreGetDeviceMem= (pCudaCoreGetDeviceMem)dlsym(m_pvCudaCoreHandle, "CudaCoreGetDeviceMem");
	m_pCudaCoreReleaseMem= (pCudaCoreReleaseMem)dlsym(m_pvCudaCoreHandle, "CudaCoreReleaseDeviceMem");
	m_pCudaCoreMemcpy2D= (pCudaCoreMemcpy2D)dlsym(m_pvCudaCoreHandle, "CudaCoreMemcpy2D");
	m_pCudaCoreGetGpuID= (pCudaCoreGetGpuID)dlsym(m_pvCudaCoreHandle, "CudaCoreGetGpuID");

	return RET_SUCCESS;

#endif
}

int	CLS_CudaDecApi::ReleaseLib()
{
	if(NULL != m_pvCudaCoreHandle)
	{
		dlclose(m_pvCudaCoreHandle);
		m_pvCudaCoreHandle = NULL;
	}

	return RET_SUCCESS;
}

