Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

How to get IKsProperySet, 4k60 Pro Mk.2 #4

Closed
washtubs opened this issue Mar 5, 2023 · 2 comments
Closed

How to get IKsProperySet, 4k60 Pro Mk.2 #4

washtubs opened this issue Mar 5, 2023 · 2 comments

Comments

@washtubs
Copy link

washtubs commented Mar 5, 2023

Sorry if this is a dumb question but I'm trying to get your sample code to work with my 4k60 Pro Mk.2. I am frankly a total novice with both windows and C++ and I'm trying to figure out how to get this IKSPropertySet thing to pass into your function EGAVDeviceProperties::EGAVDeviceProperties(IKsPropertySet* inKsPropertySet, DeviceType inDeviceType).

Alternatively a full main style function would be nice. I basically am just trying to get a CLI program that sets the HDR tonemapping.

This is my device info according to pnputil

    Instance ID:                PCI\VEN_12AB&DEV_0710&SUBSYS_000E1CFA&REV_00\4&15001d53&0&0008
    Device Description:         Game Capture 4K60 Pro MK.2
    Class Name:                 MEDIA
    Class GUID:                 {4d36e96c-e325-11ce-bfc1-08002be10318}
    Manufacturer Name:          Elgato
    Status:                     Started
    Driver Name:                oem6.inf
    Hardware IDs:               PCI\VEN_12AB&DEV_0710&SUBSYS_000E1CFA&REV_00
                                PCI\VEN_12AB&DEV_0710&SUBSYS_000E1CFA
                                PCI\VEN_12AB&DEV_0710&CC_048000
                                PCI\VEN_12AB&DEV_0710&CC_0480
    Compatible IDs:             PCI\VEN_12AB&DEV_0710&REV_00
                                PCI\VEN_12AB&DEV_0710
                                PCI\VEN_12AB&CC_048000
                                PCI\VEN_12AB&CC_0480
                                PCI\VEN_12AB
                                PCI\CC_048000
                                PCI\CC_0480
@washtubs washtubs changed the title How to get IKsProperySet How to get IKsProperySet, 4k60 Pro Mk.2 Mar 5, 2023
@opendiff
Copy link

opendiff commented Nov 5, 2023

Here's sample code that initializes COM, enumerates video input devices, finds a specific device (4K60 Pro MK.2), prints its details, manages its properties (checks for HDR status and toggles HDR tonemapping), and finally releases resources before exiting.

#include <iostream>
#include <windows.h>
#include <dshow.h>

#pragma comment(lib, "strmiids.lib")
#include "DriverInterface.h"

template <class T>
void SafeRelease(T** ppT) {
    if (*ppT) {
        (*ppT)->Release();
        *ppT = NULL;
    }
}

HRESULT InitializeCOM() {
    return CoInitializeEx(NULL, COINIT_MULTITHREADED);
}

void UninitializeCOM() {
    CoUninitialize();
}

HRESULT EnumerateDevices(REFGUID category, IEnumMoniker** ppEnum)
{
    ICreateDevEnum* pDevEnum;
    HRESULT hr = CoCreateInstance(CLSID_SystemDeviceEnum, NULL,
        CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&pDevEnum));

    if (SUCCEEDED(hr))
    {
        
        hr = pDevEnum->CreateClassEnumerator(category, ppEnum, 0);
        if (hr == S_FALSE)
        {
            hr = VFW_E_NOT_FOUND;  
        }
        pDevEnum->Release();
    }
    return hr;
}

HRESULT EnumerateVideoDevices(IEnumMoniker** ppEnum) {
    return EnumerateDevices(CLSID_VideoInputDeviceCategory, ppEnum);
}

IMoniker* Find4K60ProMK2(IEnumMoniker* pEnum) {
    IMoniker* pMoniker = NULL;
    while (pEnum->Next(1, &pMoniker, NULL) == S_OK) {
        IPropertyBag* pPropBag = NULL;
        HRESULT hr = pMoniker->BindToStorage(0, 0, IID_PPV_ARGS(&pPropBag));
        if (SUCCEEDED(hr)) {
            VARIANT varFriendlyName, varDevicePath;
            VariantInit(&varFriendlyName);
            VariantInit(&varDevicePath);

            
            hr = pPropBag->Read(L"FriendlyName", &varFriendlyName, 0);
            if (SUCCEEDED(hr)) {
                const wchar_t* expectedName = L"Game Capture 4K60 Pro MK.2";
                if (wcscmp(varFriendlyName.bstrVal, expectedName) == 0) {
                    
                    hr = pPropBag->Read(L"DevicePath", &varDevicePath, 0);
                    if (SUCCEEDED(hr)) {
                        const wchar_t* expectedPathPrefix = L"\\\\?\\pci#ven_12ab&dev_0710";
                        if (wcsncmp(varDevicePath.bstrVal, expectedPathPrefix, wcslen(expectedPathPrefix)) == 0) {
                            
                            VariantClear(&varFriendlyName);
                            VariantClear(&varDevicePath);
                            SafeRelease(&pPropBag);
                            return pMoniker; 
                        }
                    }
                }
            }
            
            VariantClear(&varFriendlyName);
            VariantClear(&varDevicePath);
            SafeRelease(&pPropBag);
        }
        SafeRelease(&pMoniker); 
    }
    return NULL; 
}

void PrintDeviceInfo(IMoniker* pMoniker) {
    if (pMoniker == NULL) {
        std::wcout << L"No moniker provided to PrintDeviceInfo." << std::endl;
        return;
    }

    IPropertyBag* pPropBag = NULL;
    HRESULT hr = pMoniker->BindToStorage(0, 0, IID_PPV_ARGS(&pPropBag));
    if (SUCCEEDED(hr)) {
        VARIANT varFriendlyName, varDevicePath;
        VariantInit(&varFriendlyName);
        VariantInit(&varDevicePath);

        
        hr = pPropBag->Read(L"FriendlyName", &varFriendlyName, 0);
        if (SUCCEEDED(hr)) {
            std::wcout << L"Friendly Name: " << varFriendlyName.bstrVal << std::endl;
        }
        else {
            std::wcout << L"Could not read Friendly Name property." << std::endl;
        }

        
        hr = pPropBag->Read(L"DevicePath", &varDevicePath, 0);
        if (SUCCEEDED(hr)) {
            std::wcout << L"Device Path: " << varDevicePath.bstrVal << std::endl;
        }
        else {
            std::wcout << L"Could not read Device Path property." << std::endl;
        }

        VariantClear(&varFriendlyName);
        VariantClear(&varDevicePath);
        SafeRelease(&pPropBag);
    }
    else {
        std::wcout << L"Could not bind moniker to storage." << std::endl;
    }
}

EGAVDeviceProperties* CreateDeviceProperties(IMoniker* pMoniker) {
    IKsPropertySet* pKsPropertySet = nullptr;
    HRESULT hr = pMoniker->BindToObject(0, 0, IID_PPV_ARGS(&pKsPropertySet));
    if (SUCCEEDED(hr)) {
        
        auto deviceProperties = new EGAVDeviceProperties(pKsPropertySet, EGAVDeviceProperties::DeviceType::GC4K60ProMK2);
        pKsPropertySet->Release(); 
        return deviceProperties;
    }
    else {
        std::wcout << L"Failed to bind to IKsPropertySet interface." << std::endl;
        return nullptr;
    }
}

class DevicePropertiesManager {
private:
    EGAVDeviceProperties* m_pDeviceProperties;

public:
    
    DevicePropertiesManager(IMoniker* pMoniker) : m_pDeviceProperties(nullptr) {
        if (pMoniker) {
            m_pDeviceProperties = CreateDeviceProperties(pMoniker);
            if (!m_pDeviceProperties) {
                std::wcerr << L"Failed to create device properties." << std::endl;
            }
        }
    }

    ~DevicePropertiesManager() {
        delete m_pDeviceProperties;
    }

    DevicePropertiesManager(const DevicePropertiesManager&) = delete;
    DevicePropertiesManager& operator=(const DevicePropertiesManager&) = delete;

    
    bool IsVideoHDR() {
        if (m_pDeviceProperties) {
            bool isHDR = false;
            HRESULT hr = m_pDeviceProperties->IsVideoHDR(isHDR);
            if (SUCCEEDED(hr)) {
                return isHDR;
            }
            std::wcerr << L"Failed to get HDR status." << std::endl;
        }
        return false;
    }

    void SetHDRTonemappingEnabled(bool enabled) {
        if (m_pDeviceProperties) {
            HRESULT hr = m_pDeviceProperties->SetHDRTonemapping(enabled);
            if (FAILED(hr)) {
                std::wcerr << L"Failed to set HDR tonemapping." << std::endl;
            }
        }
    }

    HRESULT GetHDMIHDRStatusPacket(uint8_t* outBuffer, int inBufferSize) {
        if (m_pDeviceProperties) {
            
            return m_pDeviceProperties->GetHDMIHDRStatusPacket(outBuffer, inBufferSize);
        }
        else {
            std::wcerr << L"No device properties available to get HDMI HDR status packet." << std::endl;
            return E_FAIL; 
        }
    }
};

void MainProcess() {
    IEnumMoniker* pEnum = nullptr;
    HRESULT hr = EnumerateVideoDevices(&pEnum);
    if (SUCCEEDED(hr)) {
        IMoniker* pMoniker = Find4K60ProMK2(pEnum);
        if (pMoniker != nullptr) {
            PrintDeviceInfo(pMoniker);

            
            DevicePropertiesManager device(pMoniker);

            const int HDMI_PACKET_SIZE = 32; 
            uint8_t hdmiHDRStatusPacket[HDMI_PACKET_SIZE];
            HRESULT res = device.GetHDMIHDRStatusPacket(hdmiHDRStatusPacket, HDMI_PACKET_SIZE);
            std::cout << "GetHDMIHDRStatusPacket: ";
            if (SUCCEEDED(res)) {
                std::cout << "Successful" << std::endl;

                bool isHDR = device.IsVideoHDR();
                std::wcout << L"Is Video HDR? " << (isHDR ? L"Yes" : L"No") << std::endl;

                if (isHDR) {
                    
                    bool hdrToneMapping = false;
                    device.SetHDRTonemappingEnabled(hdrToneMapping);
                    std::wcout << L"HDR Tonemapping is now set to " << (hdrToneMapping ? L"enabled" : L"disabled") << std::endl;
                }

            }
            else {
                std::cout << "Error: Unknown (0x" << std::hex << res << ")" << std::endl;
            }


            pMoniker->Release(); 
        }
        else {
            std::wcout << L"Device not found." << std::endl;
        }
        SafeRelease(&pEnum);
    }
}

int main() {
    HRESULT hr = InitializeCOM();
    if (SUCCEEDED(hr)) {
        MainProcess();
        UninitializeCOM();
    }
    return 0;
}

@washtubs
Copy link
Author

This is incredible thank you!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants