//---------------------------------------------------------------------------
//	AVFile - library for audio and video files processing
//  2002 - 2007 Stanislav Sumec <sumec@fit.vutbr.cz>
//
//	dsfilei.cpp
//  DirectShow internal class
//
//  10.2.2004
//    - first release
//---------------------------------------------------------------------------

#include "dsfilei.h"
#include <sstream>

//---------------------------------------------------------------------------
#ifdef __BORLANDC__
const GUID CLSID_SampleGrabber = {0xC1F400A0, 0x3F08, 0x11D3,{ 0x9F, 0x0B, 0x00,0x60, 0x08, 0x03,0x9E, 0x37}};
const GUID IID_ISampleGrabber = {0x6B652FFF, 0x11FE, 0x4FCE,{ 0x92, 0xAD, 0x02,0x66, 0xB5, 0xD7,0xC7, 0x8F}};
const GUID IID_ISampleGrabberCB = {0x0579154A, 0x2B53, 0x4994,{ 0xB0, 0xD0, 0xE7,0x73, 0x14, 0x8E,0xFF, 0x85}};
const GUID CLSID_NullRenderer = {0xC1F400A4, 0x3F08, 0x11D3,{ 0x9F, 0x0B, 0x00,0x60, 0x08, 0x03,0x9E, 0x37}};
#endif
const GUID CLSID_Deinterlace = {0x463D645D, 0x48F7, 0x11D4, {0x84, 0x64, 0x00, 0x08, 0xC7, 0x82, 0xA2, 0x57}};
//const GUID CLSID_RTSPSource = {0x6F470083, 0xA06D, 0x4C06, {0x86, 0x64, 0x85, 0xBB, 0xAA, 0xB4, 0x53, 0xA0}};
const GUID CLSID_MoonlightDemuxer = {0x668EE184, 0xFD2D, 0x4C72,{ 0x8E, 0x79, 0x43, 0x9A, 0x35, 0xB4, 0x38, 0xDE}};

//const GUID CLSID_RTSPSource = {0xE5B059AC, 0x65A6,0x400A, {0xA1, 0x13,  0x06,   0xF4,    0x6E,  0xB4,  0x88, 0xDD}};

const GUID CLSID_RTSPSource =
{
	0x0524CA5A, 0xA685,0x476C,
	{
		0xA9,
		0xFE, 0x57,
		0x12,
		0xFB,
		0xA3,
		0x4E, 0x9E
	}
};


//---------------------------------------------------------------------------
HRESULT TDSFileI::AddGraphToRot(IUnknown *pUnkGraph, DWORD *pdwRegister)
{
	IMoniker * pMoniker;
	IRunningObjectTable *pROT;
	WCHAR wsz[128];
	HRESULT hr;

	if (!pUnkGraph || !pdwRegister)
	{
		return E_POINTER;
	}

	if (FAILED(GetRunningObjectTable(0, &pROT)))
	{
		return E_FAIL;
	}

	wsprintfW(wsz, L"FilterGraph %08x pid %08x\0", (DWORD_PTR)pUnkGraph, GetCurrentProcessId());

	hr = CreateItemMoniker(L"!", wsz, &pMoniker);
	if (SUCCEEDED(hr))
	{
		// Use the ROTFLAGS_REGISTRATIONKEEPSALIVE to ensure a strong reference
		// to the object.  Using this flag will cause the object to remain
		// registered until it is explicitly revoked with the Revoke() method.
		//
		// Not using this flag means that if GraphEdit remotely connects
		// to this graph and then GraphEdit exits, this object registration
		// will be deleted, causing future attempts by GraphEdit to fail until
		// this application is restarted or until the graph is registered again.
		hr = pROT->Register(ROTFLAGS_REGISTRATIONKEEPSALIVE, pUnkGraph, pMoniker, pdwRegister);
		pMoniker->Release();
	}

	pROT->Release();
	return hr;
}

//---------------------------------------------------------------------------
void TDSFileI::RemoveGraphFromRot(DWORD pdwRegister)
{
	IRunningObjectTable *pROT;

	if (SUCCEEDED(GetRunningObjectTable(0, &pROT)))
	{
		pROT->Revoke(pdwRegister);
		pROT->Release();
	}
}

//---------------------------------------------------------------------------
HRESULT TDSFileI::GetPin(IBaseFilter *pFilter, PIN_DIRECTION dirrequired, int iNum, IPin **ppPin)
{
	CComPtr<IEnumPins> pEnum;
	*ppPin = NULL;

	HRESULT hr = pFilter->EnumPins(&pEnum);
	if(FAILED(hr))
	{
		return hr;
	}

	ULONG ulFound;
	IPin *pPin;
	hr = E_FAIL;

	while(S_OK == pEnum->Next(1, &pPin, &ulFound))
	{
		PIN_DIRECTION pindir = (PIN_DIRECTION)3;

		pPin->QueryDirection(&pindir);
		if(pindir == dirrequired)
		{
			if(iNum == 0)
			{
				*ppPin = pPin;  // Return the pin's interface
				hr = S_OK;      // Found requested pin, so clear error
				break;
			}
			iNum--;
		}
		pPin->Release();
	}
	return hr;
}

//---------------------------------------------------------------------------
IPin* TDSFileI::GetInPin(IBaseFilter *pFilter, int nPin)
{
	IPin *pComPin = NULL;
	GetPin(pFilter, PINDIR_INPUT, nPin, &pComPin);
	return pComPin;
}

//---------------------------------------------------------------------------
IPin* TDSFileI::GetOutPin(IBaseFilter *pFilter, int nPin)
{
	IPin *pComPin = NULL;
	GetPin(pFilter, PINDIR_OUTPUT, nPin, &pComPin);
	return pComPin;
}

//---------------------------------------------------------------------------
IPin* TDSFileI::WaitForPin(IBaseFilter *pFilter, PIN_DIRECTION dirrequired, int Num, int MSecs)
{
	const int Step = 200;
	IPin *pComPin = NULL;
	do
	{
		if (GetPin(pFilter, dirrequired, Num, &pComPin) == S_OK)
		{
			return pComPin;
		}
		MSecs -= Step;
		Sleep(Step);
	}
	while (MSecs > 0);

	return pComPin;
}

//---------------------------------------------------------------------------
std::string TDSFileI::GetDevice(IPropertyBag *pPropBag, int &UnknownCount)
{
	HRESULT hr;
	VARIANT varName;
	std::wstringstream strName;
	VariantInit(&varName);

	hr = pPropBag->Read(L"FriendlyName", &varName, 0);
	if (hr == S_OK)
	{
		strName << varName.bstrVal;
	}

	hr = pPropBag->Read(L"DevicePath", &varName, 0);
	if (hr == S_OK)
	{
		strName << L" (" << varName.bstrVal << L")";
	}

	if (strName.str().empty())
	{
		strName << L"Unknown" << UnknownCount++;
	}

	VariantClear(&varName);
	std::wstring s = strName.str();

	std::string d = "Unknown";
	int size = WideCharToMultiByte(CP_THREAD_ACP, 0, s.c_str(), s.length(), NULL, 0, NULL, NULL);
	if (size > 0)
	{
		char *c = new char[size + 1];
		if (WideCharToMultiByte(CP_THREAD_ACP, 0, s.c_str(), s.length(), c, size, NULL, NULL) > 0)
		{
			c[size] = 0;
			d = c;
		}
		delete[] c;
	}
	return d;
}

