
DEFINE_GUID(CLSID_WaveParser,
0xd51bd5a1, 0x7548, 0x11cf, 0xa5, 0x20, 0x0, 0x80, 0xc7, 0x7e, 0xf5, 0x8a);

#define SOURCE_FILE L"c:\\stuff\\6ch_96khz.wav"
#define OUTPUT_FILE L"C:\\stuff\\6ch_96khz.wma"
#define PRO_FILE _T("C:\\WMMedia\\Encoder\\Profiles\\6.1_96khz_profb.prx")
#define MAX_PROFILE_SIZE_W 4096



HRESULT FindFilter(LPWSTR FilterName, const GUID Category, IBaseFilter **ppFilter)
{
	HRESULT hr = S_OK;
	IEnumMoniker *pEnumCat = NULL;

	ICreateDevEnum *pSysDevEnum = NULL;
	if ( SUCCEEDED(hr) )
		hr = ::CoCreateInstance( CLSID_SystemDeviceEnum, NULL, 
	CLSCTX_INPROC, IID_ICreateDevEnum, (LPVOID *)&pSysDevEnum );

	if ( SUCCEEDED(hr) )
		hr = pSysDevEnum->CreateClassEnumerator(Category, &pEnumCat, 0);

	if ( SUCCEEDED(hr) )
	{
		// Enumerate the monikers.
		IMoniker *pMoniker = NULL;
		ULONG cFetched; VFW_E_DDRAW_CAPS_NOT_SUITABLE;
		while(pEnumCat->Next(1, &pMoniker, &cFetched) == S_OK)
		{
			IPropertyBag *pPropBag = NULL;
			IPropertyBag2 *pPropBag2 = NULL;
			hr = pMoniker->BindToStorage(0, 0, IID_IPropertyBag2, (LPVOID *)&pPropBag2);
			if ( SUCCEEDED(hr) )
			{
				ULONG nProps;
				pPropBag2->CountProperties(&nProps);
				pPropBag2->Release();
			}

			hr = pMoniker->BindToStorage(0, 0, IID_IPropertyBag, (LPVOID *)&pPropBag);
			if ( SUCCEEDED(hr) )
			{
				// To retrieve the filter's friendly name, do the following:
				VARIANT varName;
				VARIANT var_CLSID;
				VARIANT var_FD;
				VARIANT var_guid;
				var_CLSID.vt = VT_BSTR;
				VariantInit(&varName);
				var_FD.vt = VT_UI1 | VT_ARRAY;
				var_FD.parray = 0;     // docs say to zero this
	            hr = pPropBag->Read(L"GUID", &var_guid, NULL);
				hr = pPropBag->Read(L"CLSID", &var_CLSID, NULL);
				hr = pPropBag->Read(L"FriendlyName", &varName, 0);
	            hr = pPropBag->Read(L"FilterData", &var_FD, NULL);

				if (SUCCEEDED(hr))
				{
					CString t;
					//t.Format("CLSID:%S Friendly:%S\n", var_CLSID.bstrVal, varName.bstrVal);
					//OutputDebugString(t);
					if ( lstrcmpW( varName.bstrVal, FilterName ) == 0 )
					{
						// To create an instance of the filter, do the following:
						hr = pMoniker->BindToObject(NULL, NULL, IID_IBaseFilter, (void**)ppFilter);
					}
				}
				VariantClear(&varName);
				pPropBag->Release();
			}
			pMoniker->Release();
		}
		pEnumCat->Release();
		pSysDevEnum->Release();
	}
	return hr;
}





// Build and run an encoding graph that converts a multichannel wave file to a WMA file
// using the WMA DMO Encoder.  The AudioTypeConvert filter is also used automatically 
// in this sample if the source file does not have a WAVEFORMATEXTENSIBLE structure.
// The AudioTypeConvert filter must be registered for that step to happen.
void BuildTheOtherGraph()
{
	HRESULT hr = S_OK;

	CComPtr<IGraphBuilder>							pGraph;
	CComPtr<IBaseFilter>							source;
	CComPtr<IBaseFilter>							splitter;
	CComPtr<IBaseFilter>							compressor;
	CComPtr<IBaseFilter>							asfWriter;
	CComQIPtr<IMediaControl>						control;
	CComQIPtr<IMediaEvent>							pEvent;

	hr = pGraph.CoCreateInstance(CLSID_FilterGraph);
	if ( pGraph )
	{
		control = pGraph;
		pEvent = pGraph;
	}
	
	hr = pGraph->AddSourceFilter(SOURCE_FILE, L"Source", &source);
	if ( SUCCEEDED(hr) )
		hr = pGraph->AddFilter( source, L"WAV Source" );

    hr = splitter.CoCreateInstance(CLSID_WaveParser);
	if ( SUCCEEDED(hr) )
		hr = pGraph->AddFilter( splitter, L"WAV Splitter" );

	hr = FindFilter(L"WMAudio Encoder DMO", CLSID_AudioCompressorCategory, &compressor);
	if ( SUCCEEDED(hr) )
	{
		hr = pGraph->AddFilter( compressor, L"WMA DMO Encoder" );
	}

	hr = asfWriter.CoCreateInstance(CLSID_WMAsfWriter);
	if ( SUCCEEDED(hr) )
		hr = pGraph->AddFilter( asfWriter, L"ASF Writer" );

	CComPtr<IPin> sourcepin;
	CComPtr<IPin> sin;  // splitter input
	CComPtr<IPin> sout0; // splitter output
	CComPtr<IPin> compin;  // compressor input
	CComPtr<IPin> compout; // compressor output

	source->FindPin(L"Output", &sourcepin);
	if (splitter)
	{
		// find the splitter input pin
		splitter->FindPin(L"input pin", &sin);
		if (sin)
		{
			// connect the WAV source to the WAV Splitter
			hr = pGraph->ConnectDirect( sourcepin, sin, NULL);
			if (hr == S_OK)
			{
				// find the splitter output pin
				splitter->FindPin(L"output", &sout0); 
			}
		}
	}

	if (sout0)
	{
		// find the pins for the WMA DMO filter
		hr = compressor->FindPin(L"in0", &compin);
		hr = compressor->FindPin(L"out0", &compout);

		// Connect the WAV Splitter output pin to the WMA Compressor.  We are not using ConnectDirect
		// because we want the AudioTypeConvert filter to be inserted inbetween to make the media type
		// WAVEFORMATEXTENSIBLE as the WMA DMO Compressor desires.
		hr = pGraph->Connect(sout0, compin);
	}

	{
		CComQIPtr<IConfigAsfWriter2>				pConfigWriter;
		CComPtr<IWMProfileManager>					pProfileManager;
		CComPtr<IWMProfile>							pProfile;

		hr = WMCreateProfileManager(&pProfileManager);
		WCHAR szProfile[MAX_PROFILE_SIZE_W];
		{
			// makes the assumption that the .prx file is Unicode
			CFile prof("C:\\WMMedia\\Encoder\\Profiles\\6.1_96khz_profb.prx", CFile::modeRead);
			UINT nBytesRead = prof.Read(szProfile, MAX_PROFILE_SIZE_W*2);
			szProfile[nBytesRead/2] = 0;
		}
		hr = pProfileManager->LoadProfileByData(szProfile, &pProfile);

		pConfigWriter = asfWriter;
		if (pConfigWriter)
		{
			hr = pConfigWriter->SetParam(AM_CONFIGASFWRITER_PARAM_DONTCOMPRESS, TRUE, 0);
			hr = pConfigWriter->ConfigureFilterUsingProfile(pProfile);

			CComPtr<IPin> writerPin;
			hr = asfWriter->FindPin(L"Audio Input 01", &writerPin);
			{
				CComQIPtr<IFileSinkFilter> pFileSink;
				pFileSink = asfWriter;
				// make sure the file isn't in use by a player or this will fail
				DeleteFileW(OUTPUT_FILE);
				if (pFileSink)
					hr = pFileSink->SetFileName(OUTPUT_FILE, NULL);
			}
			// connect the WMA Compressor to the ASF Writer
			hr = pGraph->ConnectDirect(compout, writerPin, NULL);
		}
	}

	// optionally add the graph to ROT - not much use unless you use the long sample
	//DWORD dwReg = 0;
	//hr = AddGraphToRot(pGraph, &dwReg);

	hr = control->Pause();
	hr = control->Run();
	long code;
	hr = pEvent->WaitForCompletion(20000, &code);

	//RemoveGraphFromRot(dwReg);

	return;
}


