Freigeben über


Benutzerdefinierte Frame Server-Medienquelle

Dieses Thema enthält Informationen zur Implementierung einer benutzerdefinierten Medienquelle innerhalb der Frame Server-Architektur.

Optionen für AV-Stream und benutzerdefinierte Medienquelle

Bei der Entscheidung, wie Die Unterstützung des Videoaufnahmestreams innerhalb der Frame Server-Architektur bereitgestellt werden soll, gibt es zwei Standard Optionen: AV Stream und Benutzerdefinierte Medienquelle.

Das AV Stream-Modell ist das Standardmodell für Kameratreiber, das einen AV Stream-Miniporttreiber (Kernelmodustreiber) verwendet. In der Regel fallen AV Stream-Treiber in zwei Standard Kategorien: MIPI-basierte Treiber und USB-Videoklassentreiber.

Für die Option Benutzerdefinierte Medienquelle kann das Treibermodell vollständig benutzerdefinierte (proprietäre) sein oder auf einer nicht herkömmlichen Kameraquelle (z. B. Datei- oder Netzwerkquellen) basieren.

AV Stream-Treiber

Der Standard Vorteil eines AV Stream Driver-Ansatzes besteht darin, dass die PnP- und Energieverwaltung/-Geräteverwaltung bereits vom AV Stream-Framework verarbeitet werden.

Dies bedeutet jedoch auch, dass die zugrunde liegende Quelle ein physisches Gerät mit einem Kernelmodustreiber sein muss, um eine Schnittstelle mit der Hardware zu erhalten. Für UVC-Geräte wird ein Windows UVC 1.5-Klassentreiber bereitgestellt, sodass Geräte einfach ihre Firmware implementieren müssen.

Für MIPI-basierte Geräte muss der Anbieter einen eigenen AV Stream-Miniporttreiber implementieren.

Benutzerdefinierte Medienquelle

Für Quellen, deren Gerätetreiber bereits verfügbar ist (aber kein AV Stream-Miniporttreiber), oder Quellen, die nicht herkömmliche Kameraaufnahmen verwenden, ist ein AV Stream-Treiber möglicherweise nicht praktikabel. Beispielsweise passt eine IP-Kamera, die über das Netzwerk verbunden ist, nicht in ein AV Stream Driver-Modell.

In solchen Situationen wäre eine benutzerdefinierte Medienquelle, die das Frame Server-Modell verwendet, eine Alternative.

Funktionen Benutzerdefinierte Medienquelle AV Stream-Treiber
PnP und Energieverwaltung Muss vom Quell- und/oder Stubtreiber implementiert werden. Bereitgestellt durch das AV Stream-Framework
Benutzermodus-Plug-In Nicht verfügbar. Custom Media Source enthält die OEM/IHV-spezifische Benutzermoduslogik. DMFT, Platform DMFT und MFT0 für die Legacyimplementierung
Sensorgruppe Unterstützt Unterstützt
Kameraprofil V2 Unterstützt Unterstützt
Kameraprofil V1 Nicht unterstützt Unterstützt

Anforderungen an benutzerdefinierte Medienquellen

Mit der Einführung Windows-Kamera Frame Server-Diensts (als Frameserver bezeichnet) kann dies über eine benutzerdefinierte Medienquelle erreicht werden. Hierfür sind zwei Standard Komponenten erforderlich:

  • Ein Treiberpaket mit einem stubbed-Treiber, der zum Registrieren/Aktivieren einer Kamerageräteschnittstelle entwickelt wurde.

  • Eine COM-DLL, die die benutzerdefinierte Medienquelle hostet.

Die erste Anforderung ist für zwei Zwecke erforderlich:

  • Ein Überprüfungsprozess, um sicherzustellen, dass die benutzerdefinierte Medienquelle über einen vertrauenswürdigen Prozess installiert wird (das Treiberpaket erfordert eine WHQL-Zertifizierung).

  • Unterstützung für die PnP-Standardaufzählung und Ermittlung der "Kamera".

Sicherheit

Die benutzerdefinierte Medienquelle für Frame Server unterscheidet sich in Bezug auf die Sicherheit wie folgt von der generischen benutzerdefinierten Medienquelle:

  • Frame Server Custom Media Source wird als lokaler Dienst ausgeführt (nicht zu verwechseln mit lokalem System; Local Service ist ein konto mit sehr geringem Privilegierten auf Windows-Computern).

  • Frame Server Custom Media Source wird in Sitzung 0 (Systemdienstsitzung) ausgeführt und kann nicht mit dem Benutzerdesktop interagieren.

Aufgrund dieser Einschränkungen dürfen benutzerdefinierte Medienquellen von Frame Server nicht versuchen, auf geschützte Teile des Dateisystems oder auf die Registrierung zuzugreifen. Im Allgemeinen ist Lesezugriff zulässig, schreibzugriff ist jedoch nicht zulässig.

Leistung

Als Teil des Frameservermodells gibt es zwei Fälle, in denen benutzerdefinierte Medienquellen vom Frameserver instanziiert werden:

  • Während der Generierung/Veröffentlichung der Sensorgruppe.

  • Während der "Kamera"-Aktivierung

Die Generierung der Sensorgruppe erfolgt in der Regel während der Geräteinstallation und/oder des Netzzyklus. Vor diesem Hintergrund wird dringend empfohlen, dass Custom Media Sources während der Erstellung eine erhebliche Verarbeitung vermeiden und eine solche Aktivität auf die FUNKTION IMFMediaSource::Start zurückstellen. Die Sensorgruppengenerierung versucht nicht, die benutzerdefinierte Medienquelle zu starten, sondern fragt lediglich die verschiedenen verfügbaren Datenströme/Medientypen und Quell-/Stream-Attributinformationen ab.

Stubtreiber

Es gibt zwei Mindestanforderungen für das Treiberpaket und den Stubtreiber.

Der Stubtreiber kann entweder mit dem WDF (UMDF oder KMDF) oder dem WDM-Treibermodell geschrieben werden.

Die Treiberanforderungen sind:

  • Registrieren Sie Ihre Geräteschnittstelle "Kamera" (benutzerdefinierte Medienquelle) unter der Kategorie KSCATEGORY_VIDEO_CAMERA , damit sie aufgelistet werden kann.

Hinweis

Um die Enumeration durch Legacy-DirectShow-Anwendungen zuzulassen, muss sich Ihr Treiber auch unter dem KSCATEGORY_VIDEO und KSCATEGORY_CAPTURE registrieren.

  • Fügen Sie einen Registrierungseintrag unter dem Geräteschnittstellenknoten hinzu (verwenden Sie die AddReg-Direktive im Abschnitt in Ihrem Treiber INF DDInstall.Interface ), der die CoCreate-fähige CLSID Ihres COM-Objekts für Custom Media Source deklariert. Dies muss mithilfe des folgenden Registrierungswertnamens hinzugefügt werden: CustomCaptureSourceClsid.

Dadurch kann die "Kamera"-Quelle von Anwendungen ermittelt werden. Bei Aktivierung wird der Frame Server-Dienst informiert, den Aktivierungsaufruf abzufangen und ihn an die coCreated Custom Media Source weiterzuleiten.

Beispiel-INF

Das folgende Beispiel zeigt einen typischen INF für einen Custom Media Source-Stubtreiber:

;/*++
;
;Module Name:
; SimpleMediaSourceDriver.INF
;
;Abstract:
; INF file for installing the Usermode SimpleMediaSourceDriver Driver
;
;Installation Notes:
; Using Devcon: Type "devcon install SimpleMediaSourceDriver.inf root\SimpleMediaSource" to install
;
;--*/

[Version]
Signature="$WINDOWS NT$"
Class=Sample
ClassGuid={5EF7C2A5-FF8F-4C1F-81A7-43D3CBADDC98}
Provider=%ProviderString%
DriverVer=01/28/2016,0.10.1234
CatalogFile=SimpleMediaSourceDriver.cat
PnpLockdown=1

[DestinationDirs]
DefaultDestDir = 13
UMDriverCopy=13 ; copy to DriverStore
CustomCaptureSourceCopy=13

; ================= Class section =====================

[ClassInstall32]
Addreg=SimpleMediaSourceClassReg

[SimpleMediaSourceClassReg]
HKR,,,0,%ClassName%
HKR,,Icon,,-24

[SourceDisksNames]
1 = %DiskId1%,,,""

[SourceDisksFiles]
SimpleMediaSourceDriver.dll = 1,,
SimpleMediaSource.dll = 1,,

;*****************************************
; SimpleMFSource Install Section
;*****************************************

[Manufacturer]
%StdMfg%=Standard,NTamd64.10.0...25326

[Standard.NTamd64.10.0...25326]
%SimpleMediaSource.DeviceDesc%=SimpleMediaSourceWin11, root\SimpleMediaSource


;---------------- copy files
[SimpleMediaSourceWin11.NT]
Include=wudfrd.inf
Needs=WUDFRD.NT
CopyFiles=UMDriverCopy, CustomCaptureSourceCopy
AddReg = CustomCaptureSource.ComRegistration

[SimpleMediaSourceWin11.NT.Interfaces]
AddInterface = %KSCATEGORY_VIDEO_CAMERA%, %CustomCaptureSource.ReferenceString%, CustomCaptureSourceInterface
AddInterface = %KSCATEGORY_VIDEO%, %CustomCaptureSource.ReferenceString%, CustomCaptureSourceInterface
AddInterface = %KSCATEGORY_CAPTURE%, %CustomCaptureSource.ReferenceString%, CustomCaptureSourceInterface

[CustomCaptureSourceInterface]
AddReg = CustomCaptureSourceInterface.AddReg, CustomCaptureSource.ComRegistration

[CustomCaptureSourceInterface.AddReg]
HKR,,CLSID,,%ProxyVCap.CLSID%
HKR,,CustomCaptureSourceClsid,,%CustomCaptureSource.CLSID%
HKR,,FriendlyName,,%CustomCaptureSource.Desc%

[CustomCaptureSource.ComRegistration]
HKR,Classes\CLSID\%CustomCaptureSource.CLSID%,,,%CustomCaptureSource.Desc%
HKR,Classes\CLSID\%CustomCaptureSource.CLSID%\InprocServer32,,%REG_EXPAND_SZ%,%CustomCaptureSource.Location%
HKR,Classes\CLSID\%CustomCaptureSource.CLSID%\InprocServer32,ThreadingModel,,Both

[UMDriverCopy]
SimpleMediaSourceDriver.dll,,,0x00004000 ; COPYFLG_IN_USE_RENAME

[CustomCaptureSourceCopy]
SimpleMediaSource.dll,,,0x00004000 ; COPYFLG_IN_USE_RENAME

;-------------- Service installation
[SimpleMediaSourceWin11.NT.Services]
Include=wudfrd.inf
Needs=WUDFRD.NT.Services

;-------------- WDF specific section -------------
[SimpleMediaSourceWin11.NT.Wdf]
UmdfService=SimpleMediaSource, SimpleMediaSource_Install
UmdfServiceOrder=SimpleMediaSource

[SimpleMediaSource_Install]
UmdfLibraryVersion=$UMDFVERSION$
ServiceBinary=%13%\SimpleMediaSourceDriver.dll

[Strings]
ProviderString = "Microsoft Corporation"
StdMfg = "(Standard system devices)"
DiskId1 = "SimpleMediaSource Disk \#1"
SimpleMediaSource.DeviceDesc = "SimpleMediaSource Capture Source" ; what you will see under SimpleMediaSource dummy devices
ClassName = "SimpleMediaSource dummy devices" ; device type this driver will install as in device manager
WudfRdDisplayName="Windows Driver Foundation - User-mode Driver Framework Reflector"
KSCATEGORY_VIDEO_CAMERA = "{E5323777-F976-4f5b-9B55-B94699C46E44}"
KSCATEGORY_CAPTURE="{65E8773D-8F56-11D0-A3B9-00A0C9223196}"
KSCATEGORY_VIDEO="{6994AD05-93EF-11D0-A3CC-00A0C9223196}"
ProxyVCap.CLSID="{17CCA71B-ECD7-11D0-B908-00A0C9223196}"
CustomCaptureSource.Desc = "SimpleMediaSource Source"
CustomCaptureSource.ReferenceString = "CustomCameraSource"
CustomCaptureSource.CLSID = "{9812588D-5CE9-4E4C-ABC1-049138D10DCE}"
CustomCaptureSource.Location = "%13%\SimpleMediaSource.dll"
CustomCaptureSource.Binary = "SimpleMediaSource.dll"
REG_EXPAND_SZ = 0x00020000

Die obige benutzerdefinierte Medienquelle wird unter KSCATEGORY_VIDEO, KSCATEGORY_CAPTURE und KSCATEGORY_VIDEO_CAMERA registriert, um sicherzustellen, dass die "Kamera" von allen UWP- und Nicht-UWP-Apps gefunden werden kann, die nach einer STANDARD-RGB-Kamera suchen.

Wenn die benutzerdefinierte Medienquelle auch Nicht-RGB-Streams (IR, Tiefe usw.) verfügbar macht, kann sie optional auch unter der KSCATEGORY_SENSOR_CAMERA registriert werden.

Hinweis

Die meisten USB-basierten Webcams machen YUY2- und MJPG-Formate verfügbar. Aufgrund dieses Verhaltens werden viele DirectShow-Legacyanwendungen mit der Annahme geschrieben, dass YUY2/MJPG verfügbar ist. Um die Kompatibilität mit einer solchen Anwendung sicherzustellen, wird empfohlen, den YUY2-Medientyp über Ihre benutzerdefinierte Medienquelle zur Verfügung zu stellen, wenn die Kompatibilität von Legacy-Apps gewünscht ist.

Implementierung des Stubtreibers

Zusätzlich zum INF muss der Treiber-Stub auch die Kamerageräteschnittstellen registrieren und aktivieren. Dies geschieht in der Regel während des DRIVER_ADD_DEVICE-Vorgangs.

Siehe DRIVER_ADD_DEVICE Rückruffunktion für WDM-basierte Treiber und WdfDriverCreate-Funktion für UMDF-/KMDF-Treiber.

Im Folgenden ist ein Code-Snip eines UMDF-Treiberstubs aufgeführt, der diesen Vorgang verarbeitet:

NTSTATUS
DriverEntry(
    IN PDRIVER_OBJECT DriverObject,
    IN PUNICODE_STRING RegistryPath
    )
/*++

Routine Description:

    DriverEntry initializes the driver and is the first routine called by the
    system after the driver is loaded. DriverEntry specifies the other entry
    points in the function driver, such as EvtDevice and DriverUnload.

Parameters Description:

    DriverObject - represents the instance of the function driver that is loaded
    into memory. DriverEntry must initialize members of DriverObject before it
    returns to the caller. DriverObject is allocated by the system before the
    driver is loaded, and it is released by the system after the system unloads
    the function driver from memory.

RegistryPath - represents the driver specific path in the Registry.

    The function driver can use the path to store driver related data between
    reboots. The path does not store hardware instance specific data.

Return Value:

    STATUS_SUCCESS if successful,  
    STATUS_UNSUCCESSFUL otherwise.

--*/

{
    WDF_DRIVER_CONFIG config;
    NTSTATUS status;

    WDF_DRIVER_CONFIG_INIT(&config,
                    EchoEvtDeviceAdd
                    );

    status = WdfDriverCreate(DriverObject,
                            RegistryPath,
                            WDF_NO_OBJECT_ATTRIBUTES,
                            &config,
                            WDF_NO_HANDLE);

    if (!NT_SUCCESS(status)) {
        KdPrint(("Error: WdfDriverCreate failed 0x%x\n", status));
        return status;
    }

    // ...

    return status;
}

NTSTATUS
EchoEvtDeviceAdd(
    IN WDFDRIVER Driver,
    IN PWDFDEVICE_INIT DeviceInit
    )
/*++
Routine Description:

    EvtDeviceAdd is called by the framework in response to AddDevice
    call from the PnP manager. We create and initialize a device object to
    represent a new instance of the device.

Arguments:

    Driver - Handle to a framework driver object created in DriverEntry

    DeviceInit - Pointer to a framework-allocated WDFDEVICE_INIT structure.

Return Value:

    NTSTATUS

--*/
{
    NTSTATUS status;

    UNREFERENCED_PARAMETER(Driver);

    KdPrint(("Enter EchoEvtDeviceAdd\n"));

    status = EchoDeviceCreate(DeviceInit);

    return status;
}

NTSTATUS
EchoDeviceCreate(
    PWDFDEVICE_INIT DeviceInit  
/*++

Routine Description:

    Worker routine called to create a device and its software resources.

Arguments:

    DeviceInit - Pointer to an opaque init structure. Memory for this
                    structure will be freed by the framework when the WdfDeviceCreate
                    succeeds. Do not access the structure after that point.

Return Value:

    NTSTATUS

--*/  
{
    WDF_OBJECT_ATTRIBUTES deviceAttributes;
    PDEVICE_CONTEXT deviceContext;
    WDF_PNPPOWER_EVENT_CALLBACKS pnpPowerCallbacks;
    WDFDEVICE device;
    NTSTATUS status;
    UNICODE_STRING szReference;
    RtlInitUnicodeString(&szReference, L"CustomCameraSource");

    WDF_PNPPOWER_EVENT_CALLBACKS_INIT(&pnpPowerCallbacks);

    //
    // Register pnp/power callbacks so that we can start and stop the timer as the device
    // gets started and stopped.
    //
    pnpPowerCallbacks.EvtDeviceSelfManagedIoInit = EchoEvtDeviceSelfManagedIoStart;
    pnpPowerCallbacks.EvtDeviceSelfManagedIoSuspend = EchoEvtDeviceSelfManagedIoSuspend;

    #pragma prefast(suppress: 28024, "Function used for both Init and Restart Callbacks")
    pnpPowerCallbacks.EvtDeviceSelfManagedIoRestart = EchoEvtDeviceSelfManagedIoStart;

    //
    // Register the PnP and power callbacks. Power policy related callbacks will be registered
    // later in SoftwareInit.
    //
    WdfDeviceInitSetPnpPowerEventCallbacks(DeviceInit, &pnpPowerCallbacks);

    {
        WDF_FILEOBJECT_CONFIG cameraFileObjectConfig;
        WDF_OBJECT_ATTRIBUTES cameraFileObjectAttributes;

        WDF_OBJECT_ATTRIBUTES_INIT(&cameraFileObjectAttributes);

        cameraFileObjectAttributes.SynchronizationScope = WdfSynchronizationScopeNone;

        WDF_FILEOBJECT_CONFIG_INIT(
            &cameraFileObjectConfig,
            EvtCameraDeviceFileCreate,
            EvtCameraDeviceFileClose,
            WDF_NO_EVENT_CALLBACK);

        WdfDeviceInitSetFileObjectConfig(
            DeviceInit,
            &cameraFileObjectConfig,
            &cameraFileObjectAttributes);
    }

    WDF_OBJECT_ATTRIBUTES_INIT_CONTEXT_TYPE(&deviceAttributes, DEVICE_CONTEXT);

    status = WdfDeviceCreate(&DeviceInit, &deviceAttributes, &device);

    if (NT_SUCCESS(status)) {
        //
        // Get the device context and initialize it. WdfObjectGet_DEVICE_CONTEXT is an
        // inline function generated by WDF_DECLARE_CONTEXT_TYPE macro in the
        // device.h header file. This function will do the type checking and return
        // the device context. If you pass a wrong object handle
        // it will return NULL and assert if run under framework verifier mode.
        //
        deviceContext = WdfObjectGet_DEVICE_CONTEXT(device);
        deviceContext->PrivateDeviceData = 0;

        //
        // Create a device interface so that application can find and talk
        // to us.
        //
        status = WdfDeviceCreateDeviceInterface(
            device,
            &CAMERA_CATEGORY,
            &szReference // ReferenceString
            );

        if (NT_SUCCESS(status)) {
            //
            // Create a device interface so that application can find and talk
            // to us.
            //
            status = WdfDeviceCreateDeviceInterface(
            device,
            &CAPTURE_CATEGORY,
            &szReference // ReferenceString
            );
        }

        if (NT_SUCCESS(status)) {
            //
            // Create a device interface so that application can find and talk
            // to us.
            //
            status = WdfDeviceCreateDeviceInterface(
            device,
            &VIDEO_CATEGORY,
            &szReference // ReferenceString
            );
        }

        if (NT_SUCCESS(status)) {
            //
            // Initialize the I/O Package and any Queues
            //
            status = EchoQueueInitialize(device);
        }
    }

    return status;
}

PnP-Vorgang

Genau wie bei jeder anderen physischen Kamera wird empfohlen, dass Ihr Stubtreiber mindestens die PnP-Vorgänge zum Aktivieren und Deaktivieren des Geräts verwaltet, wenn die zugrunde liegende Quelle entfernt/angefügt wird. Wenn Ihre benutzerdefinierte Medienquelle beispielsweise eine Netzwerkquelle (z. B. eine IP-Kamera) verwendet, können Sie eine Geräteentfernung auslösen, wenn diese Netzwerkquelle nicht mehr verfügbar ist.

Dadurch wird sichergestellt, dass Anwendungen über die PnP-APIs auf Das Hinzufügen/Entfernen von Geräten lauschen. Und stellt sicher, dass eine Quelle, die nicht mehr verfügbar ist, nicht aufgezählt werden kann.

Informationen zu UMDF- und KMDF-Treibern finden Sie in der Dokumentation zur WdfDeviceSetDeviceState-Funktion .

Informationen zu WMD-Treibern finden Sie in der Dokumentation zur IoSetDeviceInterfaceState-Funktion .

Benutzerdefinierte Medienquellen-DLL

Die benutzerdefinierte Medienquelle ist ein com-Standardserver inproc, der die folgenden Schnittstellen implementieren muss:

Hinweis

IMFMediaSourceEx erbt von IMFMediaSource und IMFMediaSource erbt von IMFMediaEventGenerator.

Jeder unterstützte Stream innerhalb der benutzerdefinierten Medienquelle muss die folgenden Schnittstellen unterstützen:

Hinweis

IMFMediaStream2 erbt von IMFMediaStream und IMFMediaStream von IMFMediaEventGenerator.

Informationen zum Erstellen einer benutzerdefinierten Medienquelle finden Sie in der Dokumentation Schreiben einer benutzerdefinierten Medienquelle . Im weiteren Verlauf dieses Abschnitts werden die Unterschiede erläutert, die zur Unterstützung Ihrer benutzerdefinierten Medienquelle innerhalb des Frame Server-Frameworks erforderlich sind.

IMFGetService

IMFGetService ist eine obligatorische Schnittstelle für die benutzerdefinierte Frame Server-Medienquelle. IMFGetService gibt möglicherweise MF_E_UNSUPPORTED_SERVICE zurück, wenn Ihre benutzerdefinierte Medienquelle keine zusätzlichen Dienstschnittstellen verfügbar machen muss.

Das folgende Beispiel zeigt eine IMFGetService-Implementierung ohne Supportdienstschnittstellen:

_Use_decl_annotations_
IFACEMETHODIMP
SimpleMediaSource::GetService(
    _In_ REFGUID guidService,
    _In_ REFIID riid,
    _Out_ LPVOID * ppvObject
    )
{
    HRESULT hr = S_OK;
    auto lock = _critSec.Lock();

    RETURN_IF_FAILED (_CheckShutdownRequiresLock());

    if (!ppvObject)
    {
        return E_POINTER;
    }
    *ppvObject = NULL;

    // We have no supported service, just return
    // MF_E_UNSUPPORTED_SERVICE for all calls.

    return MF_E_UNSUPPORTED_SERVICE;
}

IMFMediaEventGenerator

Wie oben gezeigt, müssen sowohl die Quelle als auch die einzelnen Streams innerhalb der Quelle ihre eigene IMFMediaEventGenerator-Schnittstelle unterstützen. Die gesamten MF-Pipelinedaten- und Steuerungsdatenflüsse aus der Quelle werden über den Ereignisgenerator verwaltet, indem bestimmte IMFMediaEvent gesendet werden.

Für die Implementierung von IMFMediaEventGenerator muss die benutzerdefinierte Medienquelle die MFCreateEventQueue-API verwenden, um eine IMFMediaEventQueue zu erstellen und alle Methoden für IMFMediaEventGenerator an das Warteschlangenobjekt weiterzuleiten:

IMFMediaEventGenerator verfügt über die folgenden Methoden:

// IMFMediaEventGenerator
IFACEMETHOD(BeginGetEvent)(_In_ IMFAsyncCallback *pCallback, _In_ IUnknown *punkState);
IFACEMETHOD(EndGetEvent)(_In_ IMFAsyncResult *pResult, _COM_Outptr_ IMFMediaEvent **ppEvent);
IFACEMETHOD(GetEvent)(DWORD dwFlags, _Out_ IMFMediaEvent **ppEvent);
IFACEMETHOD(QueueEvent)(MediaEventType met, REFGUID guidExtendedType, HRESULT hrStatus, _In_opt_ const PROPVARIANT *pvValue);

Der folgende Code zeigt die empfohlene Implementierung der IMFMediaEventGenerator-Schnittstelle . Die Benutzerdefinierte Medienquelle-Implementierung macht die IMFMediaEventGenerator-Schnittstelle verfügbar, und die Methoden für diese Schnittstelle routingen die Anforderungen an das IMFMediaEventQueue-Objekt , das während der Erstellung/Initialisierung der Medienquelle erstellt wurde.

Im folgenden Code ist _spEventQueue Objekt die IMFMediaEventQueue , die mit der MFCreateEventQueue-Funktion erstellt wurde:

// IMFMediaEventGenerator methods
IFACEMETHODIMP
SimpleMediaSource::BeginGetEvent(
    _In_ IMFAsyncCallback *pCallback,
    _In_ IUnknown *punkState
    )
{
    HRESULT hr = S_OK;
    auto lock = _critSec.Lock();

    RETURN_IF_FAILED (_CheckShutdownRequiresLock());
    RETURN_IF_FAILED (_spEventQueue->BeginGetEvent(pCallback, punkState));

    return hr;
}

IFACEMETHODIMP
SimpleMediaSource::EndGetEvent(
    _In_ IMFAsyncResult *pResult,
    _COM_Outptr_ IMFMediaEvent **ppEvent
    )
{
    HRESULT hr = S_OK;
    auto lock = _critSec.Lock();

    RETURN_IF_FAILED (_CheckShutdownRequiresLock());
    RETURN_IF_FAILED (_spEventQueue->EndGetEvent(pResult, ppEvent));

    return hr;
}

IFACEMETHODIMP
SimpleMediaSource::GetEvent(
    DWORD dwFlags,
    _COM_Outptr_ IMFMediaEvent **ppEvent
    )
{
    // NOTE:
    // GetEvent can block indefinitely, so we do not hold the lock.
    // This requires some juggling with the event queue pointer.

    HRESULT hr = S_OK;

    ComPtr<IMFMediaEventQueue> spQueue;

    {
        auto lock = _critSec.Lock();

        RETURN_IF_FAILED (_CheckShutdownRequiresLock());
        spQueue = _spEventQueue;
    }

    // Now get the event.
    RETURN_IF_FAILED (spQueue->GetEvent(dwFlags, ppEvent));

    return hr;
}

IFACEMETHODIMP
SimpleMediaSource::QueueEvent(
    MediaEventType eventType,
    REFGUID guidExtendedType,
    HRESULT hrStatus,
    _In_opt_ PROPVARIANT const *pvValue
    )
{
    HRESULT hr = S_OK;
    auto lock = _critSec.Lock();

    RETURN_IF_FAILED (_CheckShutdownRequiresLock());
    RETURN_IF_FAILED (_spEventQueue->QueueEventParamVar(eventType, guidExtendedType, hrStatus, pvValue));

    return hr;
}

Suchen und Anhalten

Benutzerdefinierte Medienquellen, die über das Frame Server-Framework unterstützt werden, unterstützen keine Such- oder Pausenvorgänge. Ihre benutzerdefinierte Medienquelle muss keine Unterstützung für diese Vorgänge bereitstellen und darf weder das MFSourceSeeked - noch das MEStreamSeeked-Ereignis posten.

IMFMediaSource::P ause sollte MF_E_INVALID_STATE_TRANSITION zurückgeben (oder MF_E_SHUTDOWN , wenn die Quelle bereits heruntergefahren wurde).

IKsControl

IKsControl ist die Standard-Steuerungsschnittstelle für alle kamerabezogenen Steuerelemente. Wenn Ihre benutzerdefinierte Medienquelle Kamerasteuerelemente implementiert, wird die IKsControl-Schnittstelle verwendet, wie die Pipeline die Steuerelement-E/A weiterleitet.

Weitere Informationen finden Sie in den folgenden Dokumentationsthemen zu Steuerelementen:

Die Steuerelemente sind optional, und wenn sie nicht unterstützt werden, wird der empfohlene Fehlercode HRESULT_FROM_WIN32(ERROR_SET_NOT_FOUND) zurückgegeben.

Der folgende Code ist ein Beispiel für eine IKsControl-Implementierung ohne unterstützte Steuerelemente:

// IKsControl methods
_Use_decl_annotations_
IFACEMETHODIMP
SimpleMediaSource::KsProperty(
    _In_reads_bytes_(ulPropertyLength) PKSPROPERTY pProperty,
    _In_ ULONG ulPropertyLength,
    _Inout_updates_to_(ulDataLength, *pBytesReturned) LPVOID pPropertyData,
    _In_ ULONG ulDataLength,
    _Out_ ULONG* pBytesReturned
    )
{
    // ERROR_SET_NOT_FOUND is the standard error code returned
    // by the AV Stream driver framework when a miniport
    // driver does not register a handler for a KS operation.
    // We want to mimic the driver behavior here if we do not
    // support controls.
    return HRESULT_FROM_WIN32(ERROR_SET_NOT_FOUND);
}

_Use_decl_annotations_
IFACEMETHODIMP SimpleMediaSource::KsMethod(
    _In_reads_bytes_(ulMethodLength) PKSMETHOD pMethod,
    _In_ ULONG ulMethodLength,
    _Inout_updates_to_(ulDataLength, *pBytesReturned) LPVOID pMethodData,
    _In_ ULONG ulDataLength,
    _Out_ ULONG* pBytesReturned
    )
{
    return HRESULT_FROM_WIN32(ERROR_SET_NOT_FOUND);
}

_Use_decl_annotations_
IFACEMETHODIMP SimpleMediaSource::KsEvent(
    _In_reads_bytes_opt_(ulEventLength) PKSEVENT pEvent,
    _In_ ULONG ulEventLength,
    _Inout_updates_to_(ulDataLength, *pBytesReturned) LPVOID pEventData,
    _In_ ULONG ulDataLength,
    _Out_opt_ ULONG* pBytesReturned
    )
{
    return HRESULT_FROM_WIN32(ERROR_SET_NOT_FOUND);
}

IMFMediaStream2

Wie unter Schreiben einer benutzerdefinierten Medienquelle erläutert, wird die IMFMediaStream2-Schnittstelle für die Framearbeit von Ihrer benutzerdefinierten Medienquelle über ein MENewStream-Medienereignis bereitgestellt, das während des Abschlusses der IMFMediaSource::Start-Methode an die Quellereigniswarteschlange gesendet wurde:

IFACEMETHODIMP
SimpleMediaSource::Start(
    _In_ IMFPresentationDescriptor *pPresentationDescriptor,
    _In_opt_ const GUID *pguidTimeFormat,
    _In_ const PROPVARIANT *pvarStartPos
    )
{
    HRESULT hr = S_OK;
    auto lock = _critSec.Lock();
    DWORD count = 0;
    PROPVARIANT startTime;
    BOOL selected = false;
    ComPtr<IMFStreamDescriptor> streamDesc;
    DWORD streamIndex = 0;

    if (pPresentationDescriptor == nullptr || pvarStartPos == nullptr)
    {
        return E_INVALIDARG;
    }
    else if (pguidTimeFormat != nullptr && *pguidTimeFormat != GUID_NULL)
    {
        return MF_E_UNSUPPORTED_TIME_FORMAT;
    }

    RETURN_IF_FAILED (_CheckShutdownRequiresLock());

    if (_sourceState != SourceState::Stopped)
    {
        return MF_E_INVALID_STATE_TRANSITION;
    }

    _sourceState = SourceState::Started;

    // This checks the passed in PresentationDescriptor matches the member of streams we
    // have defined internally and that at least one stream is selected

    RETURN_IF_FAILED (_ValidatePresentationDescriptor(pPresentationDescriptor));
    RETURN_IF_FAILED (pPresentationDescriptor->GetStreamDescriptorCount(&count));
    RETURN_IF_FAILED (InitPropVariantFromInt64(MFGetSystemTime(), &startTime));

    // Send event that the source started. Include error code in case it failed.
    RETURN_IF_FAILED (_spEventQueue->QueueEventParamVar(MESourceStarted,
                                                            GUID_NULL,
                                                            hr,
                                                            &startTime));

    // We are hardcoding this to the first descriptor
    // since this sample is a single stream sample. For
    // multiple streams, we need to walk the list of streams
    // and for each selected stream, send the MEUpdatedStream
    // or MENewStream event along with the MEStreamStarted
    // event.
    RETURN_IF_FAILED (pPresentationDescriptor->GetStreamDescriptorByIndex(0,
                                                                            &selected,
                                                                            &streamDesc));

    RETURN_IF_FAILED (streamDesc->GetStreamIdentifier(&streamIndex));
    if (streamIndex >= NUM_STREAMS)
    {
        return MF_E_INVALIDSTREAMNUMBER;
    }

    if (selected)
    {
        ComPtr<IUnknown> spunkStream;
        MediaEventType met = (_wasStreamPreviouslySelected ? MEUpdatedStream : MENewStream);

        // Update our internal PresentationDescriptor
        RETURN_IF_FAILED (_spPresentationDescriptor->SelectStream(streamIndex));
        RETURN_IF_FAILED (_stream.Get()->SetStreamState(MF_STREAM_STATE_RUNNING));
        RETURN_IF_FAILED (_stream.As(&spunkStream));

        // Send the MEUpdatedStream/MENewStream to our source event
        // queue.

        RETURN_IF_FAILED (_spEventQueue->QueueEventParamUnk(met,
                                                                GUID_NULL,
                                                                S_OK,
                                                                spunkStream.Get()));

        // But for our stream started (MEStreamStarted), we post to our
        // stream event queue.
        RETURN_IF_FAILED (_stream.Get()->QueueEvent(MEStreamStarted,
                                                        GUID_NULL,
                                                        S_OK,
                                                        &startTime));
    }
    _wasStreamPreviouslySelected = selected;

    return hr;
}

Dies muss für jeden Stream erfolgen, der über den IMFPresentationDescriptor ausgewählt wird.

Für benutzerdefinierte Medienquellen mit Videostream sollten die Ereignisse MEEndOfStream und MEEndOfPresentation nicht gesendet werden.

Streamattribute

Für alle Datenströme für benutzerdefinierte Medienquellen muss die MF_DEVICESTREAM_STREAM_CATEGORYauf PINNAME_VIDEO_CAPTURE festgelegt sein. PINNAME_VIDEO_PREVIEW wird für benutzerdefinierte Medienquellen nicht unterstützt.

Hinweis

PINNAME_IMAGE wird zwar unterstützt, wird jedoch nicht empfohlen. Um einen Stream mit PINNAME_IMAGE verfügbar zu machen, muss die benutzerdefinierte Medienquelle alle Fototriggersteuerelemente unterstützen. Weitere Informationen finden Sie weiter unten im Abschnitt Fotostreamsteuerelemente .

MF_DEVICESTREAM_STREAM_ID ist ein obligatorisches Attribut für alle Streams. Es sollte sich um einen 0-basierten Index handeln. Der erste Stream hat also die ID 0, der zweite streamt die ID 1 usw.

Im Folgenden sehen Sie eine Liste der empfohlenen Attribute für den Stream:

MF_DEVICESTREAM_ATTRIBUTE_FRAMESOURCE_TYPES

MF_DEVICESTREAM_ATTRIBUTE_FRAMESOURCE_TYPES ist ein UINT32-Attribut, bei dem es sich um einen Bitmaskenwert vom Streamtyp handelt. Es kann auf einen der folgenden Typen festgelegt werden (obwohl es sich bei diesen Typen um ein Bitmaskenflag handelt, empfiehlt es sich, quelltypen möglichst nicht zu mischen):

Typ Flag Beschreibung
MFFrameSourceTypes_Color 0x0001 Standard-RGB-Farbstream
MFFrameSourceTypes_Infrared 0x0002 IR-Stream
MFFrameSourceTypes_Depth 0x0004 Tiefenstream
MFFrameSourceTypes_Image 0x0008 Bilddatenstrom (Nicht-Video-Untertyp, in der Regel JPEG)
MFFrameSourceTypes_Custom 0x0080 Benutzerdefinierter Streamtyp

MF_DEVICESTREAM_FRAMESERVER_SHARED

MF_DEVICESTREAM_FRAMESERVER_SHARED ist ein UINT32-Attribut, das entweder auf 0 oder 1 festgelegt werden kann. Wenn dieser Wert auf 1 festgelegt ist, wird der Stream vom Frameserver als "freigegeben" markiert. Dadurch können Anwendungen den Stream in einem freigegebenen Modus öffnen, auch wenn sie von einer anderen App verwendet werden.

Wenn dieses Attribut nicht festgelegt ist, lässt Frame Server die Freigabe des ersten nicht markierten Datenstroms zu (wenn die benutzerdefinierte Medienquelle nur über einen Stream verfügt, wird dieser Stream als freigegeben markiert).

Wenn dieses Attribut auf 0 festgelegt ist, blockiert Frame Server den Stream von freigegebenen Apps. Wenn die benutzerdefinierte Medienquelle alle Datenströme mit diesem Attribut markiert, das auf 0 festgelegt ist, kann keine freigegebene Anwendung die Quelle initialisieren.

Beispielzuordnung

Alle Medienframes müssen als IMFSample erstellt werden. Benutzerdefinierte Medienquellen müssen die MFCreateSample-Funktion verwenden, um eine instance von IMFSample zuzuweisen, und die AddBuffer-Methode zum Hinzufügen von Medienpuffern verwenden.

Für jedes IMFSample müssen die Stichprobenzeit und die Stichprobendauer festgelegt sein. Alle Beispielzeitstempel müssen auf der QPC-Zeit (QueryPerformanceCounter) basieren.

Es wird empfohlen, dass benutzerdefinierte Medienquellen nach Möglichkeit die MFGetSystemTime-Funktion verwenden. Diese Funktion ist ein Wrapper um QueryPerformanceCounter und konvertiert die QPC-Ticks in 100 Nanosekundeneinheiten.

Benutzerdefinierte Medienquellen können eine interne Uhr verwenden, aber alle Zeitstempel müssen basierend auf dem aktuellen QPC mit 100 Nanosekundeneinheiten korreliert werden.

Medienpuffer

Alle Medienpuffer, die dem IMFSample hinzugefügt werden, müssen die standardmäßigen MF-Pufferzuordnungsfunktionen verwenden. Benutzerdefinierte Medienquellen dürfen keine eigenen IMFMediaBuffer-Schnittstellen implementieren oder versuchen, den Medienpuffer direkt zuzuordnen (z. B. new/malloc/VirtualAlloc usw.), darf nicht für Framedaten verwendet werden.

Verwenden Sie eine der folgenden APIs, um Medienframes zuzuordnen:

MFCreateMemoryBuffer und MFCreateAlignedMemoryBuffer sollten für nicht stride ausgerichtete Mediendaten verwendet werden. In der Regel sind dies benutzerdefinierte Untertypen oder komprimierte Untertypen (z. B. H264/HEVC/MJPG).

Für bekannte unkomprimierte Medientypen (z. B. YUY2, NV12 usw.) mit Systemspeicher wird empfohlen , MFCreate2DMediaBuffer zu verwenden.

Für die Verwendung von DX-Oberflächen (für GPU-beschleunigte Vorgänge wie Rendering und/oder Codierung) sollte MFCreateDXGISurfaceBuffer verwendet werden.

MFCreateDXGISurfaceBuffer erstellt die DX-Oberfläche nicht. Die Oberfläche wird mithilfe des DXGI-Managers erstellt, der über die IMFMediaSourceEx::SetD3DManager-Methode an die Medienquelle übergeben wird.

Der IMFDXGIDeviceManager::OpenDeviceHandle stellt das Handle bereit, das dem ausgewählten D3D-Gerät zugeordnet ist. Die ID3D11Device-Schnittstelle kann dann mithilfe der IMFDXGIDeviceManager::GetVideoService-Methode abgerufen werden.

Unabhängig davon, welcher Puffertyp verwendet wird, muss das erstellte IMFSample der Pipeline über das MEMediaSample-Ereignis im IMFMediaEventGenerator des Mediendatenstroms bereitgestellt werden.

Es ist zwar möglich, dieselbe IMFMediaEventQueue sowohl für die benutzerdefinierte Medienquelle als auch für die zugrunde liegende Sammlung von IMFMediaStream zu verwenden, es sollte jedoch beachtet werden, dass dies zu einer Serialisierung der Medienquellenereignisse und Streamereignisse (einschließlich des Medienflusses) führt. Für Quellen mit mehreren Streams ist dies nicht wünschenswert.

Der folgende Codeausschnitt zeigt eine Beispielimplementierung des Mediendatenstroms:

IFACEMETHODIMP
    SimpleMediaStream::RequestSample(
    _In_ IUnknown *pToken
    )
{
    HRESULT hr = S_OK;
    auto lock = _critSec.Lock();
    ComPtr<IMFSample> sample;
    ComPtr<IMFMediaBuffer> outputBuffer;
    LONG pitch = IMAGE_ROW_SIZE_BYTES;
    BYTE *bufferStart = nullptr; // not used
    DWORD bufferLength = 0;
    BYTE *pbuf = nullptr;
    ComPtr<IMF2DBuffer2> buffer2D;

    RETURN_IF_FAILED (_CheckShutdownRequiresLock());
    RETURN_IF_FAILED (MFCreateSample(&sample));
    RETURN_IF_FAILED (MFCreate2DMediaBuffer(NUM_IMAGE_COLS,
                                            NUM_IMAGE_ROWS,
                                            D3DFMT_X8R8G8B8,
                                            false,
                                            &outputBuffer));
    RETURN_IF_FAILED (outputBuffer.As(&buffer2D));
    RETURN_IF_FAILED (buffer2D->Lock2DSize(MF2DBuffer_LockFlags_Write,
                                                &pbuf,
                                                &pitch,
                                                &bufferStart,
                                                &bufferLength));
    RETURN_IF_FAILED (WriteSampleData(pbuf, pitch, bufferLength));
    RETURN_IF_FAILED (buffer2D->Unlock2D());
    RETURN_IF_FAILED (sample->AddBuffer(outputBuffer.Get()));
    RETURN_IF_FAILED (sample->SetSampleTime(MFGetSystemTime()));
    RETURN_IF_FAILED (sample->SetSampleDuration(333333));
    if (pToken != nullptr)
    {
        RETURN_IF_FAILED (sample->SetUnknown(MFSampleExtension_Token, pToken));
    }
    RETURN_IF_FAILED (_spEventQueue->QueueEventParamUnk(MEMediaSample,
                                                            GUID_NULL,
                                                            S_OK,
                                                            sample.Get()));

    return hr;
}

Benutzerdefinierte Medienquellenerweiterung zum Verfügbarmachen von IMFActivate (verfügbar in Windows 10, Version 1809)

Zusätzlich zur obigen Liste der Schnittstellen, die für eine benutzerdefinierte Medienquelle unterstützt werden müssen, besteht eine der Einschränkungen, die durch den Benutzerdefinierten Medienquelle-Vorgang innerhalb der Frameserverarchitektur auferlegt werden, dass es nur eine instance des UMDF-Treibers geben kann, der über die Pipeline "aktiviert" wird.

Wenn Sie beispielsweise über ein physisches Gerät verfügen, das zusätzlich zum Nicht-AV Stream-Treiberpaket einen UMDF-Stubtreiber installiert, und Sie mehrere dieser physischen Geräte an einen Computer anfügen, während jedes instance des UMDF-Treibers einen eindeutigen symbolischen Linknamen erhält, verfügt der Aktivierungspfad für die benutzerdefinierte Medienquelle nicht über eine Möglichkeit, den symbolischen Linknamen zu kommunizieren, der der benutzerdefinierten Medienquelle am zugeordnet ist. Zeitpunkt der Erstellung.

Benutzerdefinierte Medienquelle sucht möglicherweise nach dem Standardattribut MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_SYMBOLIC_LINK im Attributspeicher der benutzerdefinierten Medienquelle (der Attributspeicher, der von der benutzerdefinierten Medienquelle über die IMFMediaSourceEx::GetSourceAttributes-Methode zurückgegeben wird) zum Zeitpunkt des Aufrufs von IMFMediaSource::Start .

Dies kann jedoch zu einer höheren Startwartezeit führen, da dies die HW-Ressourcenerfassung auf die Startzeit und nicht auf die Erstellungs-/Initialisierungszeit zurücksetzt.

Daher können benutzerdefinierte Medienquellen in Windows 10, Version 1809 optional eine IMFActivate-Schnittstelle verfügbar machen.

Hinweis

IMFActivate erbt von IMFAttributes.

IMFAktivieren

Wenn der COM-Server für die benutzerdefinierte Medienquelle die IMFActivate-Schnittstelle unterstützt, werden die Geräteinitialisierungsinformationen dem COM-Server über die vom IMFActivate geerbten IMFAttributes bereitgestellt. Wenn also das IMFActivate::ActivateObject aufgerufen wird, enthält der Attributspeicher des IMFActivate den symbolischen Linknamen des UMDF-Stubtreibers und alle zusätzlichen Konfigurationseinstellungen, die von der Pipeline/Anwendung zum Zeitpunkt der Erstellung/Initialisierung der Quelle bereitgestellt werden.

Die benutzerdefinierte Medienquelle sollte diesen Methodenaufruf verwenden, um alle benötigten Hardwareressourcen zu erhalten.

Hinweis

Wenn der Erwerb von Hardwareressourcen mehr als 200 Millisekunden dauert, wird empfohlen, die Hardwareressource asynchron zu erwerben. Die Aktivierung der benutzerdefinierten Medienquelle sollte die Hardwareressourcenerfassung nicht blockieren. Stattdessen sollte der IMFMediaSource::Start-Vorgang für den Hardwareressourcenerwerb serialisiert werden.

Die beiden zusätzlichen Methoden, die von IMFActivate verfügbar gemacht werden, DetachObject und ShutdownObject, müssen E_NOTIMPL zurückgeben.

Die benutzerdefinierte Medienquelle kann die IMFActivate - und DIE IMFAttributes-Schnittstelle innerhalb desselben COM-Objekts wie die IMFMediaSource implementieren. Wenn dies geschehen ist, wird empfohlen, dass IMFMediaSourceEx::GetSourceAttributes dieselbe IMFAttributes-Schnittstelle wie die von IMFActivate zurückgibt.

Wenn die benutzerdefinierte Medienquelle die IMFActivate - und DIE IMFAttributes nicht mit demselben Objekt implementiert, muss die benutzerdefinierte Medienquelle alle attribute, die im IMFActivate-Attributspeicher festgelegt sind, in den Quellattributspeicher der benutzerdefinierten Medienquelle kopieren.

Codierter Kameradatenstrom

Eine benutzerdefinierte Medienquelle kann komprimierte Medientypen (HEVC- oder H264-Elementardatenströme) verfügbar machen, und die Betriebssystempipeline unterstützt vollständig die Quelle und Konfiguration der Codierungsparameter für die benutzerdefinierte Medienquelle (die Codierungsparameter werden über die ICodecAPI kommuniziert, die als IKsControl::KsProperty-Aufruf weitergeleitet wird):

// IKsControl methods
_Use_decl_annotations_
IFACEMETHODIMP
SimpleMediaSource::KsProperty(
    _In_reads_bytes_(ulPropertyLength) PKSPROPERTY pProperty,
    _In_ ULONG ulPropertyLength,
    _Inout_updates_to_(ulDataLength, *pBytesReturned) LPVOID pPropertyData,
    _In_ ULONG ulDataLength,
    _Out_ ULONG* pBytesReturned
    );

Die an die IKsControl::KsProperty-Methode übergebene KSPROPERTY-Struktur enthält die folgenden Informationen:

KSPROPERTY.Set = Encoder Property GUID
KSPROPERTY.Id = 0
KSPROPERTY.Flags = (KSPROPERTY_TYPE_SET or KSPROPERTY_TYPE_GET)

Dabei ist die Encoder-Eigenschafts-GUID die Liste der verfügbaren Eigenschaften, die in Codec-API-Eigenschaften definiert sind.

Die Nutzlast der Encoder-Eigenschaft wird über das pPropertyData-Feld der oben deklarierten KsProperty-Methode übergeben.

Anforderungen an die Erfassungs-Engine

Während codierte Quellen von Frame Server vollständig unterstützt werden, stellt die clientseitige Erfassungs-Engine (IMFCaptureEngine), die vom Windows.Media.Capture.MediaCapture-Objekt verwendet wird, zusätzliche Anforderungen:

  • Der Stream muss entweder vollständig codiert (HEVC oder H264) oder unkomprimiert sein (in diesem Kontext wird MJPG als unkomprimiert behandelt).

  • Es muss mindestens ein nicht komprimierter Stream verfügbar sein.

Hinweis

Diese Anforderungen gelten zusätzlich zu den in diesem Thema beschriebenen Anforderungen für benutzerdefinierte Medienquellen. Die Anforderungen an die Erfassungs-Engine werden jedoch nur erzwungen, wenn die Clientanwendung die benutzerdefinierte Medienquelle über die IMFCaptureEngine - oder Windows.Media.Capture.MediaCapture-API verwendet.

Kameraprofile (verfügbar in Windows 10, Version 1803 und höher)

Kameraprofilunterstützung ist für benutzerdefinierte Medienquellen verfügbar. Der empfohlene Mechanismus besteht darin, das Profil über das MF_DEVICEMFT_SENSORPROFILE_COLLECTION-Attribut außerhalb des Quellattributs (IMFMediaSourceEx::GetSourceAttributes) zu veröffentlichen.

Das MF_DEVICEMFT_SENSORPROFILE_COLLECTION-Attribut ist ein IUnknown der IMFSensorProfileCollection-Schnittstelle . IMFSensorProfileCollection kann mithilfe der MFCreateSensorProfileCollection-Funktion abgerufen werden:

IFACEMETHODIMP
SimpleMediaSource::GetSourceAttributes(
    _COM_Outptr_ IMFAttributes** sourceAttributes
    )
{
    HRESULT hr = S_OK;
    auto lock = _critSec.Lock();

    if (nullptr == sourceAttributes)
    {
        return E_POINTER;
    }

    RETURN_IF_FAILED (_CheckShutdownRequiresLock());

    *sourceAttributes = nullptr;
    if (_spAttributes.Get() == nullptr)
    {
        ComPtr<IMFSensorProfileCollection> profileCollection;
        ComPtr<IMFSensorProfile> profile;

        // Create our source attribute store
        RETURN_IF_FAILED (MFCreateAttributes(_spAttributes.GetAddressOf(), 1));

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

        // In this example since we have just one stream, we only have one
        // pin to add: Pin0

        // 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,
                                                profile.ReleaseAndGetAddressOf()));
        RETURN_IF_FAILED (profile->AddProfileFilter(0, L"((RES==;FRT<=30,1;SUT==))"));
        RETURN_IF_FAILED (profileCollection->AddProfile(profile.Get()));

        // High Frame Rate profile will only allow >=60fps
        RETURN_IF_FAILED (MFCreateSensorProfile(KSCAMERAPROFILE_HighFrameRate, 0, nullptr,
                                                profile.ReleaseAndGetAddressOf()));
        RETURN_IF_FAILED (profile->AddProfileFilter(0, L"((RES==;FRT>=60,1;SUT==))"));
        RETURN_IF_FAILED (profileCollection->AddProfile(profile.Get()));

        // See the profile collection to the attribute store of the IMFTransform
        RETURN_IF_FAILED (_spAttributes->SetUnknown(MF_DEVICEMFT_SENSORPROFILE_COLLECTION,
                                                        profileCollection.Get()));
    }

    return _spAttributes.CopyTo(sourceAttributes);
}

Gesichtsauthentifizierungsprofil

Wenn die benutzerdefinierte Medienquelle für die Unterstützung Windows Hello Gesichtserkennung konzipiert ist, wird empfohlen, ein Profil für die Gesichtsauthentifizierung zu veröffentlichen. Die Anforderungen eines Gesichtsauthentifizierungsprofils sind:

  • Das DDI-Steuerelement für die Gesichtsauthentifizierung muss für einen einzelnen IR-Stream unterstützt werden. Weitere Informationen finden Sie unter KSPROPERTY_CAMERACONTROL_EXTENDED_FACEAUTH_MODE.

  • Der IR-Stream muss mindestens 340 x 340 bei 15 fps sein. Das Format muss entweder L8, NV12 oder MJPG sein, das mit L8-Komprimierung gekennzeichnet ist.

  • Der RGB-Stream muss mindestens 480 x 480 bei 7,5 fps sein (dies ist nur erforderlich, wenn die Multispectrumauthentifizierung erzwungen wird).

  • Das Profil für die Gesichtsauthentifizierung muss über die Profil-ID KSCAMERAPROFILE_FaceAuth_Mode,0 verfügen.

Es wird empfohlen, dass das Gesichtserkennungsprofil nur einen Medientyp für jeden IR- und RGB-Datenstrom ankündigen sollte.

Fotostream-Steuerelemente

Wenn unabhängige Fotostreams durch Markieren eines derMF_DEVICESTREAM_STREAM_CATEGORY des Streams als PINNAME_IMAGE verfügbar gemacht werden, ist ein Stream mit der Streamkategorie PINNAME_VIDEO_CAPTURE erforderlich (z. B. ist ein einzelner Stream, der nur die PINNAME_IMAGE verfügbar macht, keine gültige Medienquelle).

Über IKsControl muss der PROPSETID_VIDCAP_VIDEOCONTROL-Eigenschaftssatz unterstützt werden. Weitere Informationen finden Sie unter Videosteuerelementeigenschaften.