#include "stdafx.h"
#include "Webcam_Func_Library.h"

// safe release for COM interface pointers copied from MSDN because it is not predefined in headers
template <class T> void SafeRelease(T **ppT)
{
	if (*ppT)
	{
		(*ppT)->Release();
		*ppT = NULL;
	}
}

//
// CamCapture
//
// constructor, finds device count
CamCapture::CamCapture()
{
	IMFAttributes *pAttributes = NULL;
	IMFActivate **ppDevices = NULL;
	UINT32 count;

	// Create an attribute store to specify the enumeration parameters.
	hr = MFCreateAttributes(&pAttributes, 1);
	if (FAILED(hr))
	{
		return;
	}

	// Source type: video capture devices
	hr = pAttributes->SetGUID(MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE, MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_GUID);
	if (FAILED(hr))
	{
		return;
	}

	// Enumerate devices.
	hr = MFEnumDeviceSources(pAttributes, &ppDevices, &count);
	if (FAILED(hr))
	{
		return;
	}

	// Free all pointers from memory
	SafeRelease(&pAttributes);
	for (int j = 0; j < devCount; j++)
	{
		SafeRelease(&ppDevices[j]);
	}
	CoTaskMemFree(ppDevices);

	devCount = count;
}

// counts devices, same result as constructor
HRESULT CamCapture::CountDevices()
{
	IMFAttributes *pAttributes = NULL;
	IMFActivate **ppDevices = NULL;
	UINT32 count;

	// Create an attribute store to specify the enumeration parameters and in case of failure, return HRESULT
	hr = MFCreateAttributes(&pAttributes, 1);
	if (FAILED(hr))
	{
		return hr;
	}

	// Source type: video capture devices and in case of failure, return HRESULT
	hr = pAttributes->SetGUID(MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE, MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_GUID);
	if (FAILED(hr))
	{
		return hr;
	}

	// Enumerate devices and in case of failure, return HRESULT
	hr = MFEnumDeviceSources(pAttributes, &ppDevices, &count);
	if (FAILED(hr))
	{
		return hr;
	}

	devCount = count;

	// Free all pointers from memory
	SafeRelease(&pAttributes);
	for (int j = 0; j < devCount; j++)
	{
		SafeRelease(&ppDevices[j]);
	}
	CoTaskMemFree(ppDevices);

	return hr;
}

// get friendly name of capture device
HRESULT CamCapture::GetCamName(int id, char *name, int length)
{
	if (id < devCount)
	{
		IMFAttributes *pAttributes = NULL;
		IMFActivate **ppDevices = NULL;
		UINT32 count;

		// Create an attribute store to specify the enumeration parameters and in case of failure, return HRESULT
		hr = MFCreateAttributes(&pAttributes, 1);
		if (FAILED(hr))	
		{
			return hr;
		}

		// Source type: video capture devices and in case of failure, return HRESULT
		hr = pAttributes->SetGUID(MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE, MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_GUID);
		if (FAILED(hr))
		{
			return hr;
		}

		// Enumerate devices and in case of failure, return HRESULT
		hr = MFEnumDeviceSources(pAttributes, &ppDevices, &count);
		if (FAILED(hr))
		{
			return hr;
		}

		// windows media foundation returns friendly name to WCHAR pointer, and for user selected length
		WCHAR *nameTemp = 0;
		UINT32 nameLength = 255;

		// get capture devices friendly name and convert it to classic char array 
		hr = ppDevices[id]->GetAllocatedString(MF_DEVSOURCE_ATTRIBUTE_FRIENDLY_NAME, &nameTemp, &nameLength);
		if (SUCCEEDED(hr) && nameTemp)
		{
			int i = 0;
			while( i < length - 1 && i < nameLength &&nameTemp[i] != 0)
			{
				name[i] = (char)nameTemp[i];
				i++;
			}
			name[i] = 0;
		}

		// Free all pointers from memory
		SafeRelease(&pAttributes);
		for (int j = 0; j < devCount; j++)
		{
			SafeRelease(&ppDevices[j]);
		}
		CoTaskMemFree(ppDevices);
		CoTaskMemFree(nameTemp);
	}

	return hr;
}

HRESULT CamCapture::CreateCaptureSource(int id)
{
	//*ppSource = NULL;

	UINT32 count = 0;

	IMFAttributes *pAttributes = NULL;
	IMFActivate **ppDevices = NULL;
	IMFMediaSource *pSource = NULL;

	// Create an attribute store to hold the search criteria.
	hr = MFCreateAttributes(&pAttributes, 1);

	// Request video capture devices.
	if (SUCCEEDED(hr))
	{
		hr = pAttributes->SetGUID(MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE, MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_GUID);
	}

	// Enumerate the devices,
	if (SUCCEEDED(hr))
	{
		hr = MFEnumDeviceSources(pAttributes, &ppDevices, &count);
	}

	// Create a media source for selected device
	if (SUCCEEDED(hr))
	{
		if (count > id)
		{
			hr = ppDevices[id]->ActivateObject(IID_PPV_ARGS(&pSource));
		}
		else
		{
			hr = MF_E_NOT_FOUND;
		}
	}

	//*ppSource = pSource;

	for (DWORD i = 0; i < count; i++)
	{
		ppDevices[i]->Release();
	}

	// Free all pointers from memory
	SafeRelease(&pAttributes);
	CoTaskMemFree(ppDevices);

	return hr;
}

HRESULT CamCapture::InitCam(int id, CamData *Capture)
{
	return hr;
}

HRESULT CamCapture::DeInitCam(CamData *Capture)
{
	return hr;
}

HRESULT CamCapture::GrabFrame(int id)
{
	return hr;
}