Nuta
Dostęp do tej strony wymaga autoryzacji. Możesz spróbować się zalogować lub zmienić katalog.
Dostęp do tej strony wymaga autoryzacji. Możesz spróbować zmienić katalogi.
Ten artykuł zawiera informacje na temat implementacji niestandardowego źródła multimedialnego w architekturze Frame Server.
Opcje strumienia AV i niestandardowego źródła multimedialnego
Podczas podejmowania decyzji o sposobie zapewnienia obsługi strumienia przechwytywania wideo w architekturze Serwera ramki istnieją dwie główne opcje: AV Stream i Custom Media Source.
Model AV Stream to standardowy model sterownika aparatu wykorzystujący sterownik miniportu AV Stream (sterownik działający w trybie jądra). Zazwyczaj sterowniki usługi AV Stream należą do dwóch głównych kategorii: sterowniki oparte na interfejsie MIPI i sterowniki klasy wideo USB.
W przypadku opcji Źródło multimediów niestandardowych model sterownika może być całkowicie niestandardowy (zastrzeżony) lub może być oparty na nie tradycyjnym źródle aparatu (takim jak pliki lub źródła sieciowe).
Sterownik strumienia AV
Główną zaletą podejścia z użyciem sterownika strumieniowego AV jest to, że obsługa PnP oraz zarządzanie energią/zarządzanie urządzeniami są już realizowane przez framework AV Stream.
Jednak oznacza to również, że bazowe źródło musi być urządzeniem fizycznym ze sterownikiem trybu jądra, aby połączyć się ze sprzętem. W przypadku urządzeń UVC sterownik klasy UVC 1.5 systemu Windows jest dostarczany zintegrowany z systemem, więc urządzenia muszą jedynie zaimplementować swoje oprogramowanie układowe.
W przypadku urządzeń opartych na interfejsie MIPI dostawca musi zaimplementować własny sterownik miniportu usługi AV Stream.
Źródło multimediów niestandardowych
W przypadku źródeł, których sterownik urządzenia jest już dostępny (ale nie sterownik miniportu AV Stream) lub źródeł, które używają nietradycyjnych metod przechwytywania obrazu, sterownik strumienia AV może nie być wykonalny. Na przykład aparat IP połączony za pośrednictwem sieci nie pasuje do modelu sterownika usługi AV Stream.
W takich sytuacjach niestandardowe źródło multimedialne oparte na modelu Frame Server byłoby alternatywą.
| Funkcje | Źródło multimediów niestandardowych | Sterownik strumienia AV |
|---|---|---|
| PnP i zarządzanie energią | Musi być zaimplementowany przez sterownik źródłowy i/lub wycinkowy | Udostępniane przez strukturę usługi AV Stream |
| Wtyczka trybu użytkownika | Niedostępne. Niestandardowe źródło multimediów zawiera logikę trybu użytkownika specyficzną dla producenta OEM/IHV. | DMFT, Platforma DMFT i MFT0 do starszej implementacji |
| Grupa czujników | Wsparte | Wsparte |
| Profil kamery w wersji 2 | Wsparte | Wsparte |
| Profil kamery V1 | Niewspierane | Wsparte |
Niestandardowe wymagania dotyczące źródła multimediów
Wraz z wprowadzeniem usługi Windows Camera Frame Server (określanej jako Frame Server) można to zrobić za pośrednictwem niestandardowego źródła multimediów. Wymaga to dwóch głównych składników:
Pakiet sterowników z oszołomionym sterownikiem zaprojektowanym do rejestrowania/włączania interfejsu urządzenia z kamerą.
Biblioteka DLL COM, która hostuje źródło multimediów niestandardowych.
Pierwsze wymaganie jest wymagane w dwóch celach:
Proces weryfikacji w celu upewnienia się, że źródło multimediów niestandardowych jest zainstalowane za pośrednictwem zaufanego procesu (pakiet sterowników wymaga certyfikacji WHQL).
Obsługa standardowego wyliczenia PnP i odnajdywania "kamery".
Bezpieczeństwo
Źródło niestandardowego multimediów dla Frame Server różni się pod względem zabezpieczeń od ogólnego źródła niestandardowego multimediów w następujący sposób:
Niestandardowe Źródło Mediów Serwera Ramkowego jest uruchamiane jako usługa lokalna (nie należy mylić z Systemem Lokalnym; usługa lokalna to konto z niskimi uprawnieniami na komputerach z systemem Windows).
Źródło niestandardowego nośnika programu Frame Server jest uruchamiane w sesji 0 (sesja usługi systemowej) i nie może wchodzić w interakcje z pulpitem użytkownika.
Biorąc pod uwagę te ograniczenia, Frame Server niestandardowe źródła multimediów nie mogą próbować uzyskać dostępu do chronionych części systemu plików ani rejestru. Ogólnie rzecz biorąc, dostęp do odczytu jest dozwolony, ale dostęp do zapisu nie jest.
Wydajność
W ramach modelu Serwera ramek istnieją dwa przypadki tworzenia wystąpień niestandardowych źródeł multimediów przez serwer ramek:
Podczas procesu generowania lub publikowania grupy czujników.
Podczas aktywacji "kamery"
Generowanie grupy czujników jest zwykle wykonywane podczas instalacji urządzenia i/lub cyklu zasilania. Biorąc pod uwagę to, zdecydowanie zalecamy, aby źródła multimediów niestandardowych unikały znaczącego przetwarzania podczas tworzenia i odroczały wszelkie takie działania do funkcji IMFMediaSource::Start . Grupa generacji czujników nie będzie próbować uruchomić niestandardowego źródła multimediów, a jedynie sprawdzać dostępne strumienie, typy multimediów oraz informacje o atrybutach źródła i strumienia.
Sterownik zastępczy
Istnieją dwa minimalne wymagania dotyczące pakietu sterowników i sterownika tymczasowego.
Sterownik szkieletowy można napisać przy użyciu modelu sterowników WDF (UMDF lub KMDF) lub WDM.
Wymagania dotyczące sterownika są następujące:
- Zarejestruj interfejs urządzenia "kamera" (własne źródło multimedialne) w kategorii KSCATEGORY_VIDEO_CAMERA, aby można było go wyliczyć.
Uwaga / Notatka
Aby zezwolić na wyliczanie przez aplikacje DirectShow starszej generacji, sterownik musi również zarejestrować się pod KSCATEGORY_VIDEO i KSCATEGORY_CAPTURE.
- Dodaj wpis rejestru w węźle interfejsu urządzenia (użyj dyrektywy AddReg w sekcji INF DDInstall.Interface sterownika), który określa CLSID obiektu COM własnego źródła multimediów, który można utworzyć przy użyciu metody CoCreateInstance. Należy to dodać przy użyciu następującej nazwy wartości rejestru: CustomCaptureSourceClsid.
Dzięki temu źródło "kamery" może zostać odnalezione przez aplikacje, a po aktywacji informuje usługę Frame Server o przechwyceniu wywołania aktywacji i jego przekierowaniu do CoCreated Custom Media Source.
Przykładowa informacja
W poniższym przykładzie pokazano typowy plik INF dla sterownika stub źródła multimediów niestandardowego.
;/*++
;
;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
Powyższe niestandardowe źródło multimediów rejestruje się w KSCATEGORY_VIDEO, KSCATEGORY_CAPTURE i KSCATEGORY_VIDEO_CAMERA, aby upewnić się, że "kamera" jest odnajdywalna przez wszystkie aplikacje UWP i pozostałe aplikacje wyszukujące standardową kamerę RGB.
Jeśli źródło multimediów niestandardowych uwidacznia również strumienie inne niż RGB (IR, głębokość itd.), może opcjonalnie również zarejestrować się w zakresie KSCATEGORY_SENSOR_CAMERA.
Uwaga / Notatka
Większość kamer internetowych opartych na USB udostępnia formaty YUY2 i MJPG. Z powodu tego zachowania wiele starszych aplikacji DirectShow jest napisanych z założeniem, że formaty YUY2/MJPG są dostępne. Aby zapewnić zgodność z taką aplikacją, zaleca się udostępnienie typu danych YUY2 z niestandardowego źródła multimediów, jeśli pożądana jest zgodność ze starszymi aplikacjami.
Implementacja sterownika zastępczego
Oprócz pliku INF, stub sterownika musi również zarejestrować i włączyć interfejsy urządzeń z kamerą. Zazwyczaj odbywa się to podczas operacji DRIVER_ADD_DEVICE .
Zobacz funkcję DRIVER_ADD_DEVICE wywołania zwrotnego dla sterowników opartych na WDM oraz funkcję WdfDriverCreate dla sterowników UMDF/KMDF.
Poniżej znajduje się fragment kodu wycinka sterownika UMDF, który obsługuje tę operację:
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;
}
Operacja PnP
Podobnie jak w przypadku innych aparatów fizycznych, zaleca się, aby sterownik szkieletowy zarządzał operacjami PnP co najmniej w przypadku odłączenia/przyłączenia bazowego źródła. Jeśli na przykład źródło multimediów niestandardowych korzysta ze źródła sieciowego (takiego jak kamera IP), możesz chcieć spowodować usunięcie urządzenia, gdy to źródło sieciowe nie jest już dostępne.
Gwarantuje to, że aplikacje nasłuchujące dodawania/usuwania urządzeń za pośrednictwem interfejsów API PnP otrzymują odpowiednie powiadomienia. Zapewnia, że źródło, które nie jest już dostępne, nie może być wyliczone.
Aby uzyskać informacje o sterownikach UMDF i KMDF, zobacz dokumentację funkcji WdfDeviceSetDeviceState .
W przypadku sterowników WMD zobacz dokumentację funkcji IoSetDeviceInterfaceState .
Niestandardowa biblioteka DLL do źródeł multimediów
Źródło multimediów niestandardowych jest standardowym serwerem COM inproc, który musi implementować następujące interfejsy:
Uwaga / Notatka
IMFMediaSourceEx dziedziczy z IMFMediaSource i IMFMediaSource dziedziczy z IMFMediaEventGenerator.
Każdy obsługiwany strumień w źródle multimediów niestandardowych musi obsługiwać następujące interfejsy:
IMFMediaEventGenerator
IMFMediaStream2
Uwaga / Notatka
IMFMediaStream2 dziedziczy z IMFMediaStream i IMFMediaStream dziedziczy z IMFMediaEventGenerator.
Zapoznaj się z dokumentacją Tworzenie niestandardowego źródła multimediów, aby dowiedzieć się, jak utworzyć niestandardowe źródło multimediów. W pozostałej części tej sekcji opisano różnice wymagane do obsługi niestandardowego źródła multimediów w ramach platformy Frame Server.
IMFGetService
IMFGetService to obowiązkowy interfejs dla Frame Server Custom Media Source. IMFGetService może zwrócić MF_E_UNSUPPORTED_SERVICE , jeśli niestandardowe źródło multimediów nie musi udostępniać żadnych innych interfejsów serwisowych.
W poniższym przykładzie przedstawiono implementację IMFGetService bez interfejsów obsługi usług:
_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
Jak pokazano powyżej, zarówno źródło, jak i poszczególne strumienie w źródle muszą obsługiwać własny interfejs IMFMediaEventGenerator . Cały potok danych MF i przepływy sterowania ze źródła są zarządzane za pośrednictwem generatora zdarzeń przez wysłanie określonego IMFMediaEvent.
W celu implementacji interfejsu IMFMediaEventGenerator niestandardowe źródło multimediów musi używać interfejsu API MFCreateEventQueue do utworzenia IMFMediaEventQueue i kierować wszystkie metody odnoszące się do IMFMediaEventGenerator do obiektu kolejki.
Funkcja IMFMediaEventGenerator ma następujące metody:
// 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);
Poniższy kod przedstawia zalecaną implementację interfejsu IMFMediaEventGenerator . Implementacja źródła multimediów niestandardowych uwidacznia interfejs IMFMediaEventGenerator , a metody dla tego interfejsu rozsyłają żądania do obiektu IMFMediaEventQueue utworzonego podczas tworzenia/inicjowania źródła multimediów.
W poniższym kodzie obiekt _spEventQueue jest obiektem IMFMediaEventQueue utworzonym przy użyciu funkcji MFCreateEventQueue :
// 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;
}
Szukanie i przerywanie
Niestandardowe źródła multimediów obsługiwane za pośrednictwem platformy Frame Server nie obsługują operacji wyszukiwania ani wstrzymywania. Źródło multimediów niestandardowych nie musi zapewniać obsługi tych operacji i nie może publikować zdarzenia MFSourceSeeked lub MEStreamSeeked .
IMFMediaSource::Pause powinna zwrócić MF_E_INVALID_STATE_TRANSITION (lub MF_E_SHUTDOWN, jeśli źródło zostało już zamknięte).
IKsControl
IKsControl to standardowy interfejs sterowania dla wszystkich kontrolek związanych z kamerą. Jeśli Twoje niestandardowe źródło multimediów implementuje jakiekolwiek sterowanie kamerą, interfejs IKsControl jest sposobem, w jaki przepływ kieruje kontrolę We/Wy.
Aby uzyskać więcej informacji, zobacz następujące artykuły dokumentacji zestawu kontrolek:
Elementy sterujące są opcjonalne i jeśli nie są obsługiwane, zalecany kod błędu, który należy zwrócić, to HRESULT_FROM_WIN32(ERROR_SET_NOT_FOUND).
Poniższy kod to przykładowa implementacja IKsControl bez obsługiwanych kontrolek:
// 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
Jak wyjaśniono w artykule Pisanie niestandardowego źródła multimediów, interfejs IMFMediaStream2 jest dostarczany do frameworku z niestandardowego źródła multimediów za pośrednictwem zdarzenia multimedialnego MENewStream opublikowanego w kolejce zdarzeń źródłowych podczas wykonywania metody IMFMediaSource::Start.
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;
}
Należy to zrobić dla każdego strumienia wybranego za pośrednictwem klasy IMFPresentationDescriptor.
W przypadku niestandardowych źródeł multimediów ze strumieniem wideo nie należy wysyłać zdarzeń MEEndOfStream i MEEndOfPresentation .
Atrybuty strumienia
Wszystkie strumienie niestandardowego źródła multimediów muszą mieć ustawioną kategorię MF_DEVICESTREAM_STREAM_CATEGORY na PINNAME_VIDEO_CAPTURE. PINNAME_VIDEO_PREVIEW nie jest obsługiwana w przypadku niestandardowych źródeł multimediów.
Uwaga / Notatka
PINNAME_IMAGE, chociaż jest obsługiwana, nie jest zalecana. Ujawienie strumienia z PINNAME_IMAGE wymaga, aby niestandardowe źródło multimediów obsługiwało wszystkie kontrolki wyzwalaczy zdjęć. Aby uzyskać więcej informacji, zobacz sekcję Kontrolki strumienia zdjęć poniżej.
MF_DEVICESTREAM_STREAM_ID jest obowiązkowym atrybutem dla wszystkich strumieni. Powinien to być indeks oparty na 0. Dlatego pierwszy strumień ma identyfikator 0, drugi strumień identyfikator 1 itd.
Poniżej przedstawiono listę zalecanych atrybutów w strumieniu:
MF_DEVICESTREAM_ATTRIBUTE_FRAMESOURCE_TYPES
MF_DEVICESTREAM_ATTRIBUTE_FRAMESOURCE_TYPES jest atrybutem UINT32, który jest wartością maskowaną bitowo typu strumienia. Może być ustawiona na dowolną z następujących wartości (chociaż te typy są flagą maski bitowej, zaleca się, aby typy źródłowe nie były mieszane, jeśli w ogóle to możliwe):
| Typ | Flaga | Opis |
|---|---|---|
| MFFrameSourceTypes_Color | 0x0001 | Standardowy strumień kolorów RGB |
| MFFrameSourceTypes_Podczerwieni | 0x0002 | Strumień IR |
| MFFrameSourceTypes_Głębokość | 0x0004 | Strumień głębokości |
| TypyŹródełRamki_MF_Obraz | 0x0008 | Strumień obrazów (typ podrzędny nonvideo, zazwyczaj JPEG) |
| MFFrameSourceTypes_Niestandardowe | 0x0080 | Niestandardowy typ strumienia |
MF_DEVICESTREAM_FRAMESERVER_SHARED
MF_DEVICESTREAM_FRAMESERVER_SHARED jest atrybutem UINT32, który można ustawić na 0 lub 1. Jeśli ustawiono wartość 1, oznacza to strumień jako "współużytkowany" przez serwer frame. Dzięki temu aplikacje mogą otwierać strumień w trybie udostępnionym, nawet w przypadku użycia przez inną aplikację.
Jeśli ten atrybut nie jest ustawiony, serwer Frame Server zezwala na udostępnianie pierwszego nieoznaczonego strumienia (jeśli źródło multimediów niestandardowych ma tylko jeden strumień, ten strumień jest oznaczony jako udostępniony).
Jeśli ten atrybut ma wartość 0, serwer frame blokuje strumień z udostępnionych aplikacji. Jeśli źródło multimediów niestandardowych oznacza wszystkie strumienie z tym atrybutem ustawionym na 0, żadna udostępniona aplikacja nie może zainicjować źródła.
Przykładowa alokacja
Wszystkie ramki multimedialne muszą być produkowane jako IMFSample. Niestandardowe źródła multimediów muszą używać funkcji MFCreateSample do przydzielenia wystąpienia IMFSample oraz metody AddBuffer do dodania buforów multimediów.
Każda próbka IMFSample musi mieć ustawiony czas próbkowania i czas trwania próbki. Wszystkie przykładowe znaczniki czasu muszą być oparte na czasie QPC (QueryPerformanceCounter).
Zaleca się, aby źródła multimediów niestandardowych używały funkcji MFGetSystemTime , jeśli jest to możliwe. Ta funkcja jest opakowaniem QueryPerformanceCounter i konwertuje znaczniki QPC na jednostki 100-nanosekundowe.
Niestandardowe źródła multimediów mogą używać zegara wewnętrznego, ale wszystkie znaczniki czasu muszą być skorelowane z 100-nanosekundowymi jednostkami na podstawie bieżącego QPC.
Bufor multimediów
Wszystkie bufory multimedialne dodane do IMFSample muszą używać standardowych funkcji alokacji buforów MF. Niestandardowe źródła multimediów nie powinny realizować własnych interfejsów IMFMediaBuffer ani podejmować prób bezpośredniej alokacji bufora multimedialnego (np. new, malloc, VirtualAlloc itp. nie mogą być używane w przypadku danych ramki).
Aby przydzielić ramki multimediów, użyj dowolnego z następujących interfejsów API:
MFCreateMemoryBuffer i MFCreateAlignedMemoryBuffer powinny być używane dla nieprzyrównanych danych multimedialnych. Zazwyczaj są to niestandardowe podtypy lub skompresowane podtypy (takie jak H264/HEVC/MJPG).
W przypadku znanych nieskompresowanych typów nośników (takich jak YUY2, NV12 itd.) przy użyciu pamięci systemowej zaleca się użycie MFCreate2DMediaBuffer.
W przypadku używania powierzchni DX (w przypadku przyspieszonych operacji procesora GPU, takich jak renderowanie i/lub kodowanie), należy użyć polecenia MFCreateDXGISurfaceBuffer .
MFCreateDXGISurfaceBuffer nie tworzy powierzchni DX. Powierzchnia jest tworzona przy użyciu menedżera DXGI przekazanego do źródła multimediów za pośrednictwem metody IMFMediaSourceEx::SetD3DManager .
IMFDXGIDeviceManager::OpenDeviceHandle udostępnia uchwyt skojarzony z wybranym urządzeniem D3D. Interfejs ID3D11Device można uzyskać przy użyciu metody IMFDXGIDeviceManager::GetVideoService .
Niezależnie od typu buforu, utworzony IMFSample musi być dostarczony do potoku za pośrednictwem zdarzenia MEMediaSample na IMFMediaEventGenerator strumienia multimediów.
Chociaż można użyć tego samego IMFMediaEventQueue zarówno dla niestandardowego źródła multimediów, jak i bazowej kolekcji IMFMediaStream, należy zauważyć, że spowoduje to serializację zdarzeń źródła multimediów i zdarzeń strumienia (w tym przepływu danych multimedialnych). W przypadku źródeł z wieloma strumieniami nie jest to pożądane.
Poniższy fragment kodu przedstawia przykładową implementację strumienia multimediów:
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;
}
Rozszerzenie niestandardowego źródła multimediów w celu uwidocznienia funkcji IMFActivate (dostępnej w systemie Windows 10 w wersji 1809)
Oprócz powyższej listy interfejsów, które muszą być obsługiwane dla niestandardowego źródła multimediów, jednym z ograniczeń narzuconych przez operację niestandardowego źródła multimediów w architekturze Frame Server jest to, że w kanale może być 'aktywowane' tylko jedno wystąpienie sterownika UMDF.
Jeśli na przykład masz urządzenie fizyczne, które instaluje sterownik stub UMDF oprócz pakietu sterowników innych niż AV Stream, i dołączasz więcej niż jedno z tych urządzeń fizycznych do komputera, podczas gdy każde wystąpienie sterownika UMDF otrzyma unikatową nazwę łącza symbolicznego, ścieżka aktywacji dla niestandardowego źródła multimediów nie będzie miała sposobu przekazania nazwy łącza symbolicznego skojarzonej z niestandardowym źródłem multimediów w momencie utworzenia.
Źródło multimediów niestandardowych może wyszukać standardowy atrybut MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_SYMBOLIC_LINK w magazynie atrybutów źródła multimediów niestandardowych (magazyn atrybutów zwracany ze źródła multimediów niestandardowych za pośrednictwem metody IMFMediaSourceEx::GetSourceAttributes) w momencie wywołania IMFMediaSource::Start.
Może to jednak spowodować większe opóźnienie uruchamiania, ponieważ odroczy to pozyskiwanie zasobów sprzętowych do czasu rozpoczęcia, a nie do czasu tworzenia/inicjowania.
Z tego powodu w systemie Windows 10 w wersji 1809 niestandardowe źródła multimediów mogą opcjonalnie uwidocznić interfejs IMFActivate .
Uwaga / Notatka
IMFActivate dziedziczy z IMFAttributes.
IMFActivate
Jeśli serwer COM dla niestandardowego źródła multimediów obsługuje interfejs IMFActivate, informacje o inicjalizacji urządzenia są przekazywane do serwera COM za pośrednictwem IMFAttributes, które są inherentnie częścią IMFActivate. Dlatego po wywołaniu elementu IMFActivate::ActivateObject magazyn atrybutów IMFActivate zawiera symboliczną nazwę linku sterownika wycinkowego UMDF i wszelkie inne ustawienia konfiguracji udostępniane przez potok/aplikację w momencie tworzenia/inicjowania źródła.
Niestandardowe źródło multimediów powinno używać wywołania tej metody, aby pozyskać wszelkie potrzebne zasoby sprzętowe.
Uwaga / Notatka
Jeśli pozyskiwanie zasobów sprzętowych trwa dłużej niż 200 milisekund, zaleca się, aby takie zasoby były pozyskiwane asynchronicznie. Aktywacja źródła multimediów niestandardowych nie powinna blokować pozyskiwania zasobów sprzętowych. Zamiast tego, operację IMFMediaSource::Start należy serializować względem pozyskiwania zasobów sprzętowych.
Dwie inne metody uwidocznione przez IMFActivate, DetachObject i ShutdownObject muszą zwrócić E_NOTIMPL.
Niestandardowe źródło multimediów może postanowić zaimplementować interfejsy IMFActivate i IMFAttributes w tym samym obiekcie COM, co IMFMediaSource. W takim przypadku zaleca się, aby IMFMediaSourceEx::GetSourceAttributes zwracał ten sam interfejs IMFAttributes jak te z IMFActivate.
Jeśli źródło multimediów niestandardowych nie implementuje IMFActivate i IMFAttributes przy użyciu tego samego obiektu, źródło multimediów niestandardowych musi skopiować wszystkie atrybuty ustawione w magazynie atrybutów IMFActivate do magazynu atrybutów źródła multimediów niestandardowych.
Zakodowany strumień kamery
Źródło niestandardowego nośnika może uwidaczniać skompresowane strumienie elementarne HEVC lub H264, a ścieżka systemu operacyjnego w pełni obsługuje zarówno źródło, jak i konfigurację parametrów kodowania w źródle multimediów niestandardowych (parametry kodowania są przekazywane za pośrednictwem interfejsu ICodecAPI, który jest kierowany za pomocą wywołania IKsControl::KsProperty ).
// 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
);
Struktura KSPROPERTY przekazana do metody IKsControl::KsProperty zawiera następujące informacje:
KSPROPERTY.Set = Encoder Property GUID
KSPROPERTY.Id = 0
KSPROPERTY.Flags = (KSPROPERTY_TYPE_SET or KSPROPERTY_TYPE_GET)
Gdzie identyfikator GUID właściwości kodera jest listą dostępnych właściwości zdefiniowanych w właściwościach API kodeka.
Ładunek właściwości kodera będzie przekazywany przez pole pPropertyData w metodzie KsProperty zadeklarowanej powyżej.
Wymagania dotyczące aparatu przechwytywania
Chociaż zakodowane źródła są w pełni obsługiwane przez serwer Frame Server, silnik przechwytywania po stronie klienta (IMFCaptureEngine), który jest używany przez obiekt Windows.Media.Capture.MediaCapture, nakłada dodatkowe wymagania.
Strumień musi być albo cały zakodowany (HEVC lub H264), albo cały nieskompresowany (w tym kontekście MJPG jest traktowany jako nieskompresowany).
Musi istnieć co najmniej jeden nieskompresowany strumień.
Uwaga / Notatka
Te wymagania są dodatkiem do wymagań dotyczących źródła multimediów niestandardowych opisanych w tym artykule. Jednak wymagania silnika przechwytywania są wymuszane tylko wtedy, gdy aplikacja kliencka używa niestandardowego źródła multimediów przez API IMFCaptureEngine lub Windows.Media.Capture.MediaCapture.
Profile aparatów fotograficznych (dostępne w systemie Windows 10 w wersji 1803 lub nowszej)
Obsługa profilu aparatu jest dostępna dla niestandardowych źródeł multimediów. Zalecanym mechanizmem jest opublikowanie profilu za pomocą atrybutu MF_DEVICEMFT_SENSORPROFILE_COLLECTION poza atrybutem źródłowym (IMFMediaSourceEx::GetSourceAttributes).
Atrybut MF_DEVICEMFT_SENSORPROFILE_COLLECTION jest elementem IUnknown interfejsu IMFSensorProfileCollection . IMFSensorProfileCollection można uzyskać przy użyciu funkcji MFCreateSensorProfileCollection :
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);
}
Profil uwierzytelniania twarzy
Jeśli niestandardowe źródło multimediów jest przeznaczone do obsługi rozpoznawania twarzy Windows Hello, zaleca się opublikowanie profilu rozpoznawania twarzy. Wymagania profilu uwierzytelniania twarzy są następujące:
Kontrolka DDI uwierzytelniania twarzy musi być obsługiwana w jednym strumieniu IR. Aby uzyskać więcej informacji, zobacz KSPROPERTY_CAMERACONTROL_EXTENDED_FACEAUTH_MODE.
Strumień IR musi mieć co najmniej 340 x 340, przy 15 klatek na sekundę. Format musi być w jednym z trzech formatów: L8, NV12 lub MJPG, oznaczonym kompresją L8.
Strumień RGB musi mieć co najmniej 480 x 480 przy 7,5 kl/s (jest to wymagane tylko w przypadku wymuszania uwierzytelniania wielospektralnego).
Profil uwierzytelniania twarzy powinien mieć identyfikator profilu: KSCAMERAPROFILE_FaceAuth_Mode,0.
Zalecamy, aby profil uwierzytelniania twarzy reklamował tylko jeden typ nośnika dla każdego z strumieni IR i RGB.
Kontrolki strumienia zdjęć
Jeśli niezależne strumienie zdjęć są uwidocznione przez oznaczenie jednego zMF_DEVICESTREAM_STREAM_CATEGORY strumienia jako PINNAME_IMAGE, wymagany jest strumień z kategorią strumienia PINNAME_VIDEO_CAPTURE (na przykład pojedynczy strumień ujawniający tylko PINNAME_IMAGE nie jest prawidłowym źródłem multimediów).
Za pomocą funkcji IKsControl zestaw właściwości PROPSETID_VIDCAP_VIDEOCONTROL musi być obsługiwany. Aby uzyskać więcej informacji, zobacz Właściwości kontrolki wideo.