2

I am working on windows 10 and would like to access to video stream from my tv tuner usb device.

First of all i have tryed to use media foundation api and came to know after several searches that this API does not support tv tuner cards.

Then i have switched to directshow but enumerating video devices does not list my tv tuner device. Only my webcam is listed. I found out that i should work with filters & pins but there are no guides for such an operation.

Any help, advice or example would be helpfull.

Thanks.

K

Kattabomane
  • 124
  • 11

1 Answers1

1

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)

Community
  • 1
  • 1
Dom
  • 532
  • 1
  • 9
  • 23