I am solving the same issue this weekend :-). I would like to make a simple TV-tuner / player. The direct show seems to be last part of the developement, as you have to get data from the USB dongle.
I have searched a lot, but as you wrote, there are almost no guides unfortunately. However, I think, you could start at MS page - Microsoft TV Technologies:
https://msdn.microsoft.com/en-us/library/windows/desktop/dd695086%28v=vs.85%29.aspx?f=255&MSPPError=-2147217396
and focus on Unified Tuning Model, which leads to The Microsoft Unified Tuning Model where are some hints, how to. However, prettey close-mouthed regarding examples of code and details... This is based on MFC with OLE (I am pretty new to this technology).
Currently, I am working on part Tuning Spaces, unfortunately, there are some pitfalls, as registry permissions (I have not solved this yet).
Later, you shoud have a knowledge about filters & pins as you write. See https://msdn.microsoft.com/en-us/library/dd377601(v=vs.85).aspx.
Unfortunately, I have no Idea, how to create a graph for DVB-T. Anyway, on my dev. desktop with Win 10 the GraphEdit is crashing when I open the Direct Show Filters (probably the same reason why is crashing current SW of the DVB-T HW). I found interesting blog with alternative Graph Editor:
https://en.wikipedia.org/wiki/GraphStudio - check external links. The newer GraphStudioNext looks promising as well (I have not tried this yet).
This is the way I have just started, hope this helped if you are still interested. If you have more experience, any advices are welcomed! :-)
My testing code (not workin properly yet!) is bellow. Inspired by ITuner::put_TuneRequest() call ignored
hCo = CoInitializeEx(nullptr, COINIT::COINIT_APARTMENTTHREADED);
if (hCo == S_OK)
{
IErrorInfo* pIErrorInfo = nullptr;
HRESULT hr = S_FALSE;
// Create the SystemTuningSpaces container.
PQTuningSpaceContainer pTuningSpaceContainer; // PQTuningSpaceContaineris typedef of CComQIPtr<ITuningSpace
hr = pTuningSpaceContainer.CoCreateInstance(__uuidof(SystemTuningSpaces));
if (SUCCEEDED(hr))
{
// Get the enumerator for the collection.
CComPtr<IEnumTuningSpaces> pTuningSpaceEnum;
hr = pTuningSpaceContainer->get_EnumTuningSpaces(&pTuningSpaceEnum);
if (SUCCEEDED(hr))
{
// Loop through the collection.
PQTuningSpace pTuningSpace;
while (S_OK == pTuningSpaceEnum->Next(1, &pTuningSpace, nullptr))
{
BSTR bstrDVBValue;
pTuningSpace->get_UniqueName(&bstrDVBValue);
printf("%S\n", bstrDVBValue);
pTuningSpace->get_FriendlyName(&bstrDVBValue);
printf("%S\n", bstrDVBValue);
pTuningSpace->get_NetworkType(&bstrDVBValue);
printf("%S\n\n", bstrDVBValue);
// pTuningSpace points to the next tuning space.
// You can query this pointer for derived interfaces.
pTuningSpace.Release();
}
}
}
PQDVBTuningSpace pDVBTuningSpace;
WCHAR szDVBNameU[64] = L"DVB-T";
WCHAR szDVBNameF[64] = L"Local DVB-T Digital Antenna";
// WCHAR szDVBNetworkType[64] = L"{B2F3A67C-29DA-4C78-8831-091ED509A475}";
WCHAR szDVBNetworkType[64] = L"{216C62DF-6D7F-4e9a-8571-05F14EDB766A}"; // DVB-T Network type
hr = pDVBTuningSpace.CoCreateInstance(__uuidof(DVBTuningSpace));
if (FAILED(hr))
{
printf("Failed to create system tuning spaces object.");
return;
}
hr = pDVBTuningSpace->put_SystemType(DVBSystemType::DVB_Terrestrial);
if (FAILED(hr))
{
printf("Failed to put system type of tuning space.");
return;
}
hr = pDVBTuningSpace->put_NetworkType(szDVBNetworkType);
if (FAILED(hr))
{
printf("Failed to put network type of tuning space.");
return;
}
BSTR bstrDVBNetworkType = SysAllocString(szDVBNetworkType);
hr = pDVBTuningSpace->put_NetworkType(bstrDVBNetworkType);
SysFreeString(bstrDVBNetworkType);
if (FAILED(hr))
{
printf("Failed to put network type of tuning space.");
return;
}
BSTR bstrDVBName = nullptr;
bstrDVBName = SysAllocString(szDVBNameU);
hr = pDVBTuningSpace->put_UniqueName(bstrDVBName);
SysFreeString(bstrDVBName);
bstrDVBName = SysAllocString(szDVBNameF);
hr = pDVBTuningSpace->put_FriendlyName(bstrDVBName);
SysFreeString(bstrDVBName);
if (FAILED(hr))
{
printf("Failed to put name of tuning space.");
return;
}
PQDVBTLocator pDVBTLocator;
hr = pDVBTLocator.CoCreateInstance(__uuidof(DVBTLocator));
hr = pDVBTLocator->put_CarrierFrequency(538000);
hr = pDVBTLocator->put_Bandwidth(8);
hr = pDVBTuningSpace->put_DefaultLocator(pDVBTLocator);
if (FAILED(hr))
{
printf("Failed to put locator of tuning space.");
return;
}
VARIANT tiIndex = {};
//PQTuningSpaceContainer pTuningSpaceContainer;
//hr = pTuningSpaceContainer.CoCreateInstance(__uuidof(SystemTuningSpaces));
hr = pTuningSpaceContainer->Add(pDVBTuningSpace, &tiIndex); // #fix needed: registry permissions
if (hr == HRESULT_FROM_WIN32(ERROR_DUP_NAME))
{
CComPtr<IEnumTuningSpaces> pTuningSpaceEnum;
hr = pTuningSpaceContainer->get_EnumTuningSpaces(&pTuningSpaceEnum);
if (SUCCEEDED(hr))
{
// Loop through the collection.
PQTuningSpace pTuningSpace;
tiIndex.intVal = 0;
while (S_OK == pTuningSpaceEnum->Next(1, &pTuningSpace, nullptr))
{
CComBSTR name;
hr = pTuningSpace->get_UniqueName(&name);
if (SUCCEEDED(hr))
{
if (name == szDVBNameU)
{
hr = pTuningSpaceContainer->put_Item(tiIndex, pDVBTuningSpace); // #fix needed: E_INVALIDARG One or more arguments are invalid.
break;
}
}
tiIndex.intVal++;
pTuningSpace.Release();
}
}
}
PQTuneRequest pTuneRequest;
hr = pDVBTuningSpace->CreateTuneRequest(&pTuneRequest);
if (FAILED(hr))
{
printf("Failed to create tune request.");
return;
}
PQDVBTuneRequest pDVBTuneRequest(pTuneRequest);
if (pDVBTuneRequest)
{
hr = pDVBTuneRequest->put_SID(-1);
hr = pDVBTuneRequest->put_TSID(-1);
hr = pDVBTuneRequest->put_ONID(-1);
}
CComPtr<IGraphBuilder> pGraph;
hr = CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX::CLSCTX_INPROC_SERVER, IID_IGraphBuilder, (void **)&pGraph);
CComPtr<IBaseFilter> pNetworkProvider;
GUID CLSIDNetworkType;
hr = pDVBTuningSpace->get__NetworkType(&CLSIDNetworkType);
hr = CoCreateInstance(CLSIDNetworkType, NULL, CLSCTX::CLSCTX_INPROC_SERVER, IID_IBaseFilter, (void **)&pNetworkProvider);
hr = pGraph->AddFilter(pNetworkProvider, L"Network Provider");
//// Query for ITuner.
CComQIPtr<ITuner> pTuner(pNetworkProvider);
if (pTuner)
{
// Submit the tune request to the network provider.
hr = pTuner->put_TuneRequest(pTuneRequest);
}
// TODO: What next???
CoUninitialize();
EDIT:
this could help a lot:
https://github.com/dgis/CodeTV
(checked and works for me)