(相机配置文件 V2) 的示例代码

以下部分包含演示如何使用新 API 图面的示例代码。 每个部分都介绍示例代码的方案。

示例 1

IHV/OEM 提供的设备 MFT 需要提供基础传感器和 ISP 支持的一组相机配置文件。 这是在 Device MFT 的 IMFDeviceTransform::InitializeTransform () 方法期间发布的。

必须在连接的转换的 IMFAttributes 存储上设置提供的相机配置文件, (管道完全构造) 后,这是管道查询的存储。

此示例是 IHV 附带启用了配置文件的单个参考驱动程序包的典型情况,但是 OEM 可能会选择将相机模块与不同的传感器模块配对。 在这种情况下,由于传感器的功能可能不同,因此需要对配置文件进行运行时更新。 这由 DMFT 完成。

IFACEMETHODIMP
SampleDMFT::InitializeTransform(
    _In_ IMFAttributes *pAttributes 
    )
{
    ComPtr<IMFTransform>                spTransform;
    ComPtr<IMFAttributes>               spAttributes;
    ComPtr<IMFSensorProfileCollection>  spProfileCollection;
    ComPtr<IMFSensorProfile>            spProfile;


    if (nullptr == pAttributes)
    {
        return E_INVALIDARG;
    }

    // Get the connected KSCONTROL interface, this is the 
    // IMFTransform of the up stream transform--which will
    // be the devproxy if only one DMFT is present, or
    // will be forwarded by the platform DMFT if that is
    // in between the IHV/OEM DMFT and devproxy.
    // In either case, the IHV/OEM DMFT won't need to know
    // the topology.
    RETURN_IF_FAILED (pAttributes->GetUnknown(MF_DEVICEMFT_CONNECTED_FILTER_KSCONTROL, 
                                              IID_PPV_ARGS(&spTransform)));
    RETURN_IF_FAILED (spTransform->GetAttributes(&spAttributes));

    // Create an empty profile collection...
    RETURN_IF_FAILED (MFCreateSensorProfileCollection(&spProfileCollection));

    // In this example:
    // Pin0 - Preview pin.
    // Pin1 - Capture/Record pin.
    // Pin2 - Photo pin.
    // Pin3 - IR pin.
    // 
    // Legacy profile is mandatory.  This is to ensure non-profile
    // aware applications can still function, but with degraded
    // feature sets.
    RETURN_IF_FAILED (MFCreateSensorProfile(KSCAMERAPROFILE_Legacy, 0, nullptr, 
                                            spProfile.ReleaseAndGetAddressOf()));
    RETURN_IF_FAILED (spProfile->AddProfileFilter(0, L"((RES==;FRT<=30,1;SUT==))"));
    RETURN_IF_FAILED (spProfile->AddProfileFilter(1, L"((RES==;FRT<=30,1;SUT==))"));
    RETURN_IF_FAILED (spProfile->AddProfileFilter(2, L"((RES==;FRT<=30,1;SUT==))"));
    RETURN_IF_FAILED (spProfile->AddProfileFilter(3, L"((RES==;FRT<=30,1;SUT==))"));
    RETURN_IF_FAILED (spProfileCollection->AddProfile(spProfile));

    // High Frame Rate profile will only allow preview & record/capture pin.
    RETURN_IF_FAILED (MFCreateSensorProfile(KSCAMERAPROFILE_HighFrameRate, 0, nullptr, 
                                            spProfile.ReleaseAndGetAddressOf()));
    RETURN_IF_FAILED (spProfile->AddProfileFilter(0, L"((RES==;FRT==;SUT==))"));
    RETURN_IF_FAILED (spProfile->AddProfileFilter(1, L"((RES==;FRT>=60,1;SUT==))"));
    RETURN_IF_FAILED (spProfile->AddProfileFilter(2, L"(!)"));
    RETURN_IF_FAILED (spProfile->AddProfileFilter(3, L"(!)"));
    RETURN_IF_FAILED (spProfileCollection->AddProfile(spProfile));

    // HighQualityPhoto profile will only allow preview and photo pin.
    RETURN_IF_FAILED (MFCreateSensorProfile(KSCAMERAPROFILE_HighQualityPhoto, 0, nullptr, 
                                            spProfile.ReleaseAndGetAddressOf()));
    RETURN_IF_FAILED (spProfile->AddProfileFilter(0, L"((RES==;FRT==;SUT==))"));
    RETURN_IF_FAILED (spProfile->AddProfileFilter(1, L"(!)"));
    RETURN_IF_FAILED (spProfile->AddProfileFilter(2, L"((RES==;FRT==;SUT==))"));
    RETURN_IF_FAILED (spProfile->AddProfileFilter(3, L"(!)"));
    RETURN_IF_FAILED (spProfileCollection->AddProfile(spProfile));

    // Face auth only allows 720p@30fps from preview and any from IR pin.
    RETURN_IF_FAILED (MFCreateSensorProfile(KSCAMERAPROFILE_FaceAuth_Mode, 0, nullptr, 
                                            spProfile.ReleaseAndGetAddressOf()));
    RETURN_IF_FAILED (spProfile->AddProfileFilter(0, L"((RES==1280,720;FRT==30,1;SUT==))"));
    RETURN_IF_FAILED (spProfile->AddProfileFilter(1, L"(!)"));
    RETURN_IF_FAILED (spProfile->AddProfileFilter(2, L"(!)"));
    RETURN_IF_FAILED (spProfile->AddProfileFilter(3, L"((RES==;FRT==;SUT==))"));
    RETURN_IF_FAILED (spProfileCollection->AddProfile(spProfile));


    // Se the profile collection to the attribute store of the IMFTransform.
    RETURN_IF_FAILED (spAttributes->SetUnknown(MF_DEVICEMFT_SENSORPROFILE_COLLECTION, 
                                               spProfileCollection));

    // ... Rest of the InitializeTransform logic...
}

示例 2

在此方案中,我们假设 IHV/OEM 提供了传感器组转换 (SGT) ,它合成来自多个物理设备的媒体流。 我们还假设 IHV 为每个物理设备的相机驱动程序提供了单个参考实现, (可能来自不同供应商) ,但 OEM (或其他 IHV) 已选择将相机驱动程序与不同的传感器和/或 ISP 配对。

这会导致引用实现声明的某些功能不再有效。 SGT 将更新/删除提供的配置文件,以便更准确地描述基础硬件的功能。

以下示例是 IMFSensorTransformFactory::InitializeFactory 方法的实现。 这由为相机子系统生成驱动程序包的 IHV/OEM 实现。

IFACEMETHODIMP
SampleSensorTransformFactory::InitializeFactory(
    _In_ DWORD dwMaxTransformCount, 
    _In_ IMFCollection* sensorDevices, 
    _In_opt_ IMFAttributes* pAttributes 
    )
{
    DWORD sensorDeviceCount = 0;
    ComPtr<IUnknown> unknown;

    if (nullptr == sensorDevices)
    {
        return E_INVALIDARG;
    }

    // For this example, the IHV/OEM added a SGT to a multi-camera
    // setup.  And the SGT is responsible for updating the profile
    // information available from each of the physical cameras, and
    // leave it's own profile as "blank".  This has the net effect
    // of having the SGT support any profile the physical devices
    // expose.
    RETURN_IF_FAILED (sensorDevices->GetElementCount(&sensorDeviceCount));
    for (DWORD idx = 0; idx < sensorDeviceCount; idx++)
    {
        ComPtr<IMFGetService> service;
        ComPtr<IMFSensorProfileCollection> profileCollection;
        SENSORPROFILEID sensorProfileId;

        RETURN_IF_FAILED (sensorDevices->GetElement(idx, 
                              unknown.ReleaseAndGetAddressOf()));
        RETURN_IF_FAILED (unknown.As(service.ReleaseAndGetAddressOf()));
        RETURN_IF_FAILED (service->GetService(GUID_NULL, 
                              ID_PPV_ARGS(profileCollection.ReleaseAndGetAddressOf())));

        // Let's assume that for this ISP/sensor, we cannot support
        // photo sequence but our reference driver published a single
        // photo sequence profile whose ID is hardcoded to a static
        // variable s_PhotoSequenceProfileId.
        RETURN_IF_FAILED (profileCollection->RemoveProfile(&s_PhotoSequenceProfileId));

        // Let's also assume this is a low cost ISP/sensor so our driver
        // cannot support Video HDR (VHDR) control for high frame rate
        // recording and our reference implementation published multiple
        // high frame rate recording profile.
        // 
        // Also for this combination of ISP/sensor, we cannot support
        // Face Auth (IR doesn't support alternate illumination option).
        // So we need to remove all Face Auth from our collection.
        for (DWORD profileIdx = 0; 
                   profileIdx < profileCollection->GetProfileCount();)
        {
            ComPtr<IMFSensorProfile> profile;

            RETURN_IF_FAILED (profileCollection->GetProfile(profileIdx, 
                                  profile.ReleaseAndGetAddressOf()));

            RETURN_IF_FAILED (profile->GetProfileId(&profileId));
            if (profileId.Type == KSCAMERAPROFILE_HighFrameRate)
            {
                RETURN_IF_FAILED (profile->AddBlockedControl(L"VHDR"));
            }
            if (profileId.Type == KSCAMERAPROFILE_FaceAuth_Mode)
            {
                RETURN_IF_FAILED (profileCollection->RemoveProfileByIndex(profileIdx));
            }
            else
            {
                profileIdx++;
            }
        }
    }

    // ... Rest of the InitializeFactory logic...
}

示例 3

根据特定设备的所选配置文件,使用 IMFSensorStream 信息确定该配置文件支持/不支持该设备的媒体类型。

此示例旨在说明如何在直接使用 Win32 API 时在客户端空间中使用配置文件。 通过 CameraProfile API 使用时,WinRT API 已实现此逻辑。

HRESULT
CheckMediaTypesOnPin(
    _In_z_ LPCWSTR deviceSymbolicName,
    _In_ UINT32 pinId,
    _In_ SENSORPROFILEID* profileId,
    _COM_Outptr_ IMFCollection** mediaTypeCollection
    )
{
    HRESULT hr = S_OK;
    ComPtr<IMFCollection> collection;
    ComPtr<IMFSensorGroup> sensorGroup;
    ComPtr<IMFGetService> service;
    ComPtr<IMFSensorProfileCollection> profileCollection;
    ComPtr<IMFSensorProfile> profile;
    ComPtr<IMFSensorStream> sensorStream;
    DWORD deviceCount = 0;
    DWORD streamCount = 0;
    DWORD mediaTypeCount = 0;

    // Validate in params.
    if (nullptr == deviceSymbolicName || nullptr == profileId)
    {
        return E_INVALIDARG;
    }
    if (pinId == (UINT32)-1)
    {
        return MF_E_INVALIDSTREAMNUMBER;
    }
    if (nullptr == mediaTypeCollection)
    {
        return E_POINTER;
    }
    *mediaTypeCollection = nullptr;

    RETURN_IF_FAILED (MFCreateCollection(collection.ReleaseAndGetAddressOf()));

    // Create the SensorGroup for our device name.  This device name
    // can be a single physical device name or it can be a multi-device
    // group of devices.  In either case, MFCreateSensorGroup will create
    // a non-activated snapshot of the device(s).
    RETURN_IF_FAILED (MFCreateSensorGroup(deviceSymbolicName, &sensorGroup));
    RETURN_IF_FAILED (sensorGroup.As(service.ReleaseAndGetAddressOf()));

    // Now check if they have a profile collection.
    RETURN_IF_FAILED (service->GetService(GUID_NULL, 
                          IID_PPV_ARGS(profileCollection.ReleaseAndGetAddressOf())));

    if (profileCollection->GetProfileCount() != 0)
    {
        // If they published profiles, but we can't find the specific
        // profile, it means this camera doesn't support that scenario
        // so we should return an empty collection of media types to
        // indicate no support.
        if (FAILED(profileCollection->FindProfile(profileId, 
                       profile.ReleaseAndGetAddressOf())))
        {
            *mediaTypeCollection = collection.Detach();
            return S_OK;
        }
    }

    // If profiles are not supported, then ALL media types are
    // supported.  And we can indicate that by keeping the
    // profile null.  So we have to walk the sensor stream
    // but that means we have to find the sensor stream for
    // the pinId.
    RETURN_IF_FAILED (sensorGroup->GetSensorDeviceCount(&deviceCount));
    for (DWORD deviceIdx = 0; deviceIdx < deviceCount && 
                              sensorStream.Get() == nullptr; deviceIdx++)
    {
        RETURN_IF_FAILED (sensorGroup->GetSensorDevice(deviceIdx, 
                              sensorDevice.ReleaseAndGetAddressOf()));

        RETURN_IF_FAILED (sensorDevice->GetStreamAttributesCount(MFSensorStreamType_Output, 
                              &streamCount));
        
        for (DWORD streamIdx = 0; streamIdx < streamCount; streamIdx++)
        {
            RETURN_IF_FAILED (sensorDevice->GetStreamAttributes(
                                  MFSensorStreamType_Output, 
                                  streamIdx, 
                                  &streamAttributes));

            if (MFGetAttributesUINT32(streamAttributes, 
                                      MF_DEVICESTREAM_STREAM_ID, 
                                      (UINT32) -1) == pinId)
            {
                RETURN_IF_FAILED (streamAttributes.As(sensorStream.ReleaseAndGetAddressOf()));
                break;
            }
        }
    }

    // If we didn't find a sensorStream for the PinId, then we
    // were given bad data....
    if (sensorStream.Get() == nullptr)
    {
        return MF_E_INVALIDSTREAMNUMBER;
    }
    RETURN_IF_FAILED (sensorStream->GetMediaTypeCount(&mediaTypeCount));
    for (DWORD mediaTypeIdx = 0; mediaTypeIdx < mediaTypeCount; mediaTypeIdx++)
    {
        ComPtr<IMFMediaType> mediaType;

        RETURN_IF_FAILED (sensorStream->GetMediaType(mediaTypeIdx, 
                                                     mediaType.ReleaseAndGetAddressOf()));
        if (profile.Get() != nullptr)
        {
            BOOL supported = FALSE;

            RETURN_IF_FAILED (profile->IsMediaTypeSupported(pinId, 
                                                            mediaType.Get(),
                                                             &supported));
            if (supported)
            {
                RETURN_IF_FAILED (collection->AddElement(mediaType.Get()));
            }
        }
        else
        {
            RETURN_IF_FAILED (collection->AddElement(mediaType.Get()));
        }
    }

    *mediaTypeCollection = collection.Detach();

    return S_OK;
}

相机配置文件 V2 开发人员规范