Compare commits

...

4 commits

Author SHA1 Message Date
thyintel 58921f2aa8
Merge 411f873a56 into 9d67bf2662 2024-06-27 09:35:37 -04:00
Ryan Foster 9d67bf2662 Revert "plugins/win-dshow: Add CUDA decoder"
This reverts commit ce4c99be4e.

This was causing infinitely looping log errors in systems with no
CUDA-capable hardware when hardware decoding was enabled on video
capture devices with custom config enabled.
2024-06-26 18:43:09 -04:00
Gale 411f873a56 win-mf: Add Intel NPU AI Features 2024-05-28 15:02:04 -07:00
Gale eb98d6759a win-mf: Add Windows Media Foundation Capture Device 2024-05-28 15:02:04 -07:00
21 changed files with 4519 additions and 2 deletions

View file

@ -0,0 +1,97 @@
#[=======================================================================[.rst
FindWIL
-------
FindModule for WIL and associated headers
Imported Targets
^^^^^^^^^^^^^^^^
.. versionadded:: 3.0
This module defines the :prop_tgt:`IMPORTED` target ``WIL::WIL``.
Result Variables
^^^^^^^^^^^^^^^^
This module sets the following variables:
``WIL_FOUND``
True, if headers were found.
``WIL_VERSION``
Detected version of found WIL headers.
Cache variables
^^^^^^^^^^^^^^^
The following cache variables may also be set:
``WIL_INCLUDE_DIR``
Directory containing ``cppwinrt.h``.
#]=======================================================================]
# cmake-format: off
# cmake-lint: disable=C0103
# cmake-lint: disable=C0301
# cmake-format: on
find_package(PkgConfig QUIET)
if(PKG_CONFIG_FOUND)
pkg_search_module(_WIL QUIET wil)
endif()
find_path(
WIL_INCLUDE_DIR
NAMES wil/cppwinrt.h
HINTS ${_WI_INCLUDE_DIRS} ${_WIL_INCLUDE_DIRS}
PATHS /usr/include /usr/local/include /opt/local/include /sw/include
DOC "WIL include directory")
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(
WIL
REQUIRED_VARS WIL_INCLUDE_DIR
VERSION_VAR WIL_VERSION REASON_FAILURE_MESSAGE "${WIL_ERROR_REASON}")
mark_as_advanced(WIL_INCLUDE_DIR)
unset(WIL_ERROR_REASON)
if(EXISTS "${WIL_INCLUDE_DIR}/wil/cppwinrt.h")
file(STRINGS "${WIL_INCLUDE_DIR}/wil/cppwinrt.h" _version_string REGEX "^.*VERSION_(MAJOR|MINOR)[ \t]+[0-9]+[ \t]*$")
string(REGEX REPLACE ".*VERSION_MAJOR[ \t]+([0-9]+).*" "\\1" _version_major "${_version_string}")
string(REGEX REPLACE ".*VERSION_MINOR[ \t]+([0-9]+).*" "\\1" _version_minor "${_version_string}")
set(WIL_VERSION "${_version_major}.${_version_minor}")
unset(_version_major)
unset(_version_minor)
else()
if(NOT WIL_FIND_QUIETLY)
message(AUTHOR_WARNING "Failed to find WIL version.")
endif()
set(WIL_VERSION 0.0.0)
endif()
if(CMAKE_HOST_SYSTEM_NAME MATCHES "Darwin|Windows")
set(WIL_ERROR_REASON "Ensure that obs-deps is provided as part of CMAKE_PREFIX_PATH.")
elseif(CMAKE_HOST_SYSTEM_NAME MATCHES "Linux|FreeBSD")
set(WIL_ERROR_REASON "Ensure WIL headers are available in local library paths.")
endif()
if(WIL_FOUND)
set(WIL_INCLUDE_DIRS ${WIL_INCLUDE_DIR})
if(NOT TARGET WIL::WIL)
add_library(WIL::WIL INTERFACE IMPORTED)
set_target_properties(WIL::WIL PROPERTIES INTERFACE_INCLUDE_DIRECTORIES "${WIL_INCLUDE_DIRS}")
endif()
endif()
include(FeatureSummary)
set_package_properties(
WIL PROPERTIES
URL "https://github.com/microsoft/wil.git"
DESCRIPTION
"The Windows Implementation Libraries (WIL) is a header-only C++ library created to make life easier for developers on Windows through readable type-safe C++ interfaces for common Windows coding patterns."
)

View file

@ -0,0 +1,97 @@
#[=======================================================================[.rst
FindWIL
-------
FindModule for WIL and associated headers
Imported Targets
^^^^^^^^^^^^^^^^
.. versionadded:: 3.0
This module defines the :prop_tgt:`IMPORTED` target ``WIL::WIL``.
Result Variables
^^^^^^^^^^^^^^^^
This module sets the following variables:
``WIL_FOUND``
True, if headers were found.
``WIL_VERSION``
Detected version of found WIL headers.
Cache variables
^^^^^^^^^^^^^^^
The following cache variables may also be set:
``WIL_INCLUDE_DIR``
Directory containing ``cppwinrt.h``.
#]=======================================================================]
# cmake-format: off
# cmake-lint: disable=C0103
# cmake-lint: disable=C0301
# cmake-format: on
find_package(PkgConfig QUIET)
if(PKG_CONFIG_FOUND)
pkg_search_module(_WIL QUIET wil)
endif()
find_path(
WIL_INCLUDE_DIR
NAMES wil/cppwinrt.h
HINTS ${_WI_INCLUDE_DIRS} ${_WIL_INCLUDE_DIRS}
PATHS /usr/include /usr/local/include /opt/local/include /sw/include
DOC "WIL include directory")
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(
WIL
REQUIRED_VARS WIL_INCLUDE_DIR
VERSION_VAR WIL_VERSION REASON_FAILURE_MESSAGE "${WIL_ERROR_REASON}")
mark_as_advanced(WIL_INCLUDE_DIR)
unset(WIL_ERROR_REASON)
if(EXISTS "${WIL_INCLUDE_DIR}/wil/cppwinrt.h")
file(STRINGS "${WIL_INCLUDE_DIR}/wil/cppwinrt.h" _version_string REGEX "^.*VERSION_(MAJOR|MINOR)[ \t]+[0-9]+[ \t]*$")
string(REGEX REPLACE ".*VERSION_MAJOR[ \t]+([0-9]+).*" "\\1" _version_major "${_version_string}")
string(REGEX REPLACE ".*VERSION_MINOR[ \t]+([0-9]+).*" "\\1" _version_minor "${_version_string}")
set(WIL_VERSION "${_version_major}.${_version_minor}")
unset(_version_major)
unset(_version_minor)
else()
if(NOT WIL_FIND_QUIETLY)
message(AUTHOR_WARNING "Failed to find WIL version.")
endif()
set(WIL_VERSION 0.0.0)
endif()
if(CMAKE_HOST_SYSTEM_NAME MATCHES "Darwin|Windows")
set(WIL_ERROR_REASON "Ensure that obs-deps is provided as part of CMAKE_PREFIX_PATH.")
elseif(CMAKE_HOST_SYSTEM_NAME MATCHES "Linux|FreeBSD")
set(WIL_ERROR_REASON "Ensure WIL headers are available in local library paths.")
endif()
if(WIL_FOUND)
set(WIL_INCLUDE_DIRS ${WIL_INCLUDE_DIR})
if(NOT TARGET WIL::WIL)
add_library(WIL::WIL INTERFACE IMPORTED)
set_target_properties(WIL::WIL PROPERTIES INTERFACE_INCLUDE_DIRECTORIES "${WIL_INCLUDE_DIRS}")
endif()
endif()
include(FeatureSummary)
set_package_properties(
WIL PROPERTIES
URL "https://github.com/microsoft/wil.git"
DESCRIPTION
"The Windows Implementation Libraries (WIL) is a header-only C++ library created to make life easier for developers on Windows through readable type-safe C++ interfaces for common Windows coding patterns."
)

View file

@ -72,6 +72,7 @@ if(OBS_CMAKE_VERSION VERSION_GREATER_EQUAL 3.0.0)
add_obs_plugin(vlc-video WITH_MESSAGE)
add_obs_plugin(win-capture PLATFORMS WINDOWS)
add_obs_plugin(win-dshow PLATFORMS WINDOWS)
add_obs_plugin(win-mf PLATFORMS WINDOWS)
add_obs_plugin(win-wasapi PLATFORMS WINDOWS)
return()
@ -94,6 +95,7 @@ endfunction()
if(OS_WINDOWS)
add_subdirectory(coreaudio-encoder)
add_subdirectory(win-wasapi)
add_subdirectory(win-mf)
add_subdirectory(win-dshow)
add_subdirectory(win-capture)
add_subdirectory(decklink)

View file

@ -23,8 +23,10 @@
#endif
enum AVHWDeviceType hw_priority[] = {
AV_HWDEVICE_TYPE_CUDA, AV_HWDEVICE_TYPE_D3D11VA, AV_HWDEVICE_TYPE_DXVA2,
AV_HWDEVICE_TYPE_QSV, AV_HWDEVICE_TYPE_NONE,
AV_HWDEVICE_TYPE_D3D11VA,
AV_HWDEVICE_TYPE_DXVA2,
AV_HWDEVICE_TYPE_QSV,
AV_HWDEVICE_TYPE_NONE,
};
static bool has_hw_type(const AVCodec *c, enum AVHWDeviceType type)

View file

@ -0,0 +1,41 @@
cmake_minimum_required(VERSION 3.24...3.25)
legacy_check()
find_package(FFmpeg REQUIRED avcodec avutil)
find_package(WIL REQUIRED)
add_library(win-mf MODULE)
add_library(OBS::mf ALIAS win-mf)
target_sources(win-mf PUBLIC mf-plugin.cpp win-mf.cpp)
add_library(libmfcapture INTERFACE)
add_library(OBS::libmfcapture ALIAS libmfcapture)
target_include_directories(libmfcapture INTERFACE libmfcapture libmfcapture/source)
target_sources(libmfcapture INTERFACE libmfcapture/source/DeviceControlChangeListener.cpp
libmfcapture/source/mfcapture.cpp libmfcapture/source/PhysicalCamera.cpp)
configure_file(cmake/windows/obs-module.rc.in win-mf.rc)
target_sources(win-mf PRIVATE win-mf.rc)
target_precompile_headers(win-mf PRIVATE <wil/cppwinrt.h> <wil/result.h> <wil/com.h>)
target_link_libraries(
win-mf
PRIVATE OBS::libobs
OBS::w32-pthreads
OBS::winrt-headers
FFmpeg::avcodec
FFmpeg::avutil
strmiids
winmm
dxcore
dxguid
libmfcapture)
# cmake-format: off
set_target_properties_obs(win-mf PROPERTIES FOLDER plugins/win-mf PREFIX "")
# cmake-format: on

View file

@ -0,0 +1,64 @@
project(win-mf)
find_package(FFmpeg REQUIRED COMPONENTS avcodec avutil)
find_package(WIL REQUIRED)
add_library(win-mf MODULE)
add_library(OBS::mf ALIAS win-mf)
target_sources(win-mf PRIVATE mf-plugin.cpp plugin-macros.generated.h win-mf.cpp)
add_library(libmfcapture INTERFACE)
add_library(OBS::libmfcapture ALIAS libmfcapture)
target_sources(
libmfcapture
INTERFACE libmfcapture/mfcapture.hpp
libmfcapture/source/DeviceControlChangeListener.cpp
libmfcapture/source/DeviceControlChangeListener.hpp
libmfcapture/source/mfcapture.cpp
libmfcapture/source/framework.hpp
libmfcapture/source/mfcapture.rc
libmfcapture/source/PhysicalCamera.cpp
libmfcapture/source/PhysicalCamera.hpp
libmfcapture/source/resource.hpp)
target_include_directories(libmfcapture INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/libmfcapture)
target_compile_definitions(libmfcapture INTERFACE _UP_WINDOWS=1)
set(MODULE_DESCRIPTION "OBS MediaFoundation module")
configure_file(${CMAKE_SOURCE_DIR}/cmake/bundle/windows/obs-module.rc.in win-mf.rc)
target_sources(win-mf PRIVATE win-mf.rc)
target_compile_definitions(win-mf PRIVATE UNICODE _UNICODE _CRT_SECURE_NO_WARNINGS _CRT_NONSTDC_NO_WARNINGS OBS_LEGACY)
target_link_libraries(
win-mf
PRIVATE OBS::libobs
OBS::w32-pthreads
setupapi
strmiids
ksuser
winmm
wmcodecdspuuid
FFmpeg::avcodec
FFmpeg::avutil
dxcore
dxguid
libmfcapture)
source_group(
"libmfcapture\\Source Files"
FILES libmfcapture/source/DeviceControlChangeListener.cpp libmfcapture/source/mfcapture.cpp
libmfcapture/source/mfcapture.rc libmfcapture/source/PhysicalCamera.cpp)
source_group(
"libmfcapture\\Header Files"
FILES libmfcapture/source/DeviceControlChangeListener.hpp libmfcapture/source/framework.hpp
libmfcapture/source/mfcapture.hpp libmfcapture/source/PhysicalCamera.hpp libmfcapture/source/resource.hpp)
set_target_properties(win-mf PROPERTIES FOLDER "plugins/win-mf")
setup_plugin_target(win-mf)

View file

@ -0,0 +1,24 @@
1 VERSIONINFO
FILEVERSION ${OBS_VERSION_MAJOR},${OBS_VERSION_MINOR},${OBS_VERSION_PATCH},0
BEGIN
BLOCK "StringFileInfo"
BEGIN
BLOCK "040904B0"
BEGIN
VALUE "CompanyName", "${OBS_COMPANY_NAME}"
VALUE "FileDescription", "OBS Media Foundation module"
VALUE "FileVersion", "${OBS_VERSION_CANONICAL}"
VALUE "ProductName", "${OBS_PRODUCT_NAME}"
VALUE "ProductVersion", "${OBS_VERSION_CANONICAL}"
VALUE "Comments", "${OBS_COMMENTS}"
VALUE "LegalCopyright", "${OBS_LEGAL_COPYRIGHT}"
VALUE "InternalName", "win-mf"
VALUE "OriginalFilename", "win-mf"
END
END
BLOCK "VarFileInfo"
BEGIN
VALUE "Translation", 0x0409, 0x04B0
END
END

View file

@ -0,0 +1,65 @@
# media foundation video capture device text
VideoCaptureDevice="Video Capture Device 2"
Device="Device"
ColorSpace="Color Space"
ColorSpace.Default="Default"
ColorSpace.709="Rec. 709"
ColorSpace.601="Rec. 601"
ColorSpace.2100PQ="Rec. 2100 (PQ)"
ColorSpace.2100HLG="Rec. 2100 (HLG)"
ColorRange="Color Range"
ColorRange.Default="Default"
ColorRange.Partial="Limited"
ColorRange.Full="Full"
ConfigureAudio="Configure Audio"
ConfigureVideo="Video Effect Control"
ConfigureCrossbar="Configure Crossbar"
ResFPSType="Resolution/FPS Type"
ResFPSType.Custom="Custom"
ResFPSType.DevPreferred="Device Default"
FPS.Matching="Match Output FPS"
FPS.Highest="Highest FPS"
Resolution="Resolution"
VideoFormat="Video Format"
VideoFormat.Any="Any"
VideoFormat.Unknown="Unknown (%1)"
AudioOutputMode="Audio Output Mode"
AudioOutputMode.Capture="Capture audio only"
AudioOutputMode.DirectSound="Output desktop audio (DirectSound)"
AudioOutputMode.WaveOut="Output desktop audio (WaveOut)"
UseCustomAudioDevice="Use custom audio device"
AudioDevice="Audio Device"
Buffering="Buffering"
Buffering.ToolTip="When enabled, buffers video/audio data to ensure the smoothest and most\naccurate playback possible, but at the cost of increased latency. When using\nbuffering with a video capture card, it's recommended to set the card and the\nprogram to the same framerate for best results.\n\nWhen disabled, ensures lowest latency playback, but at the cost of frame\nplayback accuracy. This is ideal for face cameras, or when you want to use the\nprogram's preview window to play a console.\n\nAuto-detect (default) sets it to enabled if the device has delay, and disabled\nif it has no delay."
Buffering.AutoDetect="Auto-Detect"
Buffering.Enable="Enable"
Buffering.Disable="Disable"
Activate="Activate"
Deactivate="Deactivate"
FlipVertically="Flip Vertically"
Autorotation="Apply rotation data from camera (if any)"
HardwareDecode="Use hardware decoding when available"
DeactivateWhenNotShowing="Deactivate when not showing"
#if 0
MEPFilters.Title="MEP Filters"
MEPFilters.Enabled="Enabled"
MEPFilters.Disabled="Disabled"
MEPFilters.BlurStandard="Blur (Standard)"
MEPFilters.BlurPortrait="Blur (Portrait)"
MEPFilters.AutoFrame="Auto Framing"
MEPFilters.EyeContact="Eye Contact"
#endif
# Intel NPU text
IntelNPU.BackgroundBlur="Background Blur"
IntelNPU.BlurNone="None"
IntelNPU.BlurStandard="Standard Blur (Intel AI Boost)"
IntelNPU.Portrait="Portrait Blur (Intel AI Boost)"
IntelNPU.BackgroundRemoval="Background Removal (Intel AI Boost)"
IntelNPU.AutoFraming="Auto Framing (Intel AI Boost)"
IntelNPU.EyeGazeCorrection="Eye Contact Correction (Intel AI Boost)"
# encoder text
Bitrate="Bitrate"
Encoder.C985="AVerMedia H.264 Encoder (c985)"
Encoder.C353="AVerMedia H.264 Encoder"

View file

@ -0,0 +1,90 @@
#pragma once
#include <Windows.h>
#ifdef MFCAPTURE_EXPORTS
#define MFCAPTURE_EXPORTS __declspec(dllexport)
#else
#define MFCAPTURE_EXPORTS
#endif
#ifdef __cplusplus
extern "C" {
#endif
enum MF_COLOR_FORMAT {
MF_COLOR_FORMAT_UNKNOWN,
MF_COLOR_FORMAT_NV12,
MF_COLOR_FORMAT_ARGB,
MF_COLOR_FORMAT_XRGB
};
typedef HANDLE CAPTURE_DEVICE_HANDLE;
typedef void(__stdcall *MF_VideoDataCallback)(void *pData, int Size,
long long llTimestamp,
void *pUserData);
typedef void(__stdcall *MF_EnumerateCameraCallback)(const wchar_t *Name,
const wchar_t *DevId,
void *pUserData);
typedef void(__stdcall *MF_EnumerateStreamCapabilitiesCallback)(
UINT32 Width, UINT32 Height, UINT32 FpsN, UINT32 FpsD, void *pUserData);
MFCAPTURE_EXPORTS HRESULT MF_EnumerateCameras(MF_EnumerateCameraCallback cb,
void *pUserData);
MFCAPTURE_EXPORTS CAPTURE_DEVICE_HANDLE MF_Create(const wchar_t *DevId);
MFCAPTURE_EXPORTS void MF_Destroy(CAPTURE_DEVICE_HANDLE h);
MFCAPTURE_EXPORTS HRESULT MF_Prepare(CAPTURE_DEVICE_HANDLE h);
MFCAPTURE_EXPORTS HRESULT MF_EnumerateStreamCapabilities(
CAPTURE_DEVICE_HANDLE h, MF_EnumerateStreamCapabilitiesCallback cb,
void *pUserData);
// if llInterval is 0, set the camera to us the max fps
// otherwise, set camera with matching fps.
MFCAPTURE_EXPORTS HRESULT MF_SetOutputResolution(CAPTURE_DEVICE_HANDLE h,
UINT32 uiWidth,
UINT32 uiHeight,
LONGLONG llInterval,
MF_COLOR_FORMAT fmt);
// LONGLONG llInterval = 10000000ll * uiFpsD / uiFpsN;
MFCAPTURE_EXPORTS HRESULT MF_GetOutputResolution(CAPTURE_DEVICE_HANDLE h,
UINT32 *uiWidth,
UINT32 *uiHeight,
UINT32 *uiFpsN,
UINT32 *uiFpsD);
MFCAPTURE_EXPORTS HRESULT MF_Start(CAPTURE_DEVICE_HANDLE h,
MF_VideoDataCallback cb, void *pUserData);
MFCAPTURE_EXPORTS HRESULT MF_Stop(CAPTURE_DEVICE_HANDLE h);
MFCAPTURE_EXPORTS HRESULT MF_GetBlur(CAPTURE_DEVICE_HANDLE h, bool &blur,
bool &shallowFocus, bool &mask);
MFCAPTURE_EXPORTS HRESULT MF_SetBlur(CAPTURE_DEVICE_HANDLE h, BOOL blur,
BOOL shallowFocus, BOOL mask);
MFCAPTURE_EXPORTS HRESULT MF_GetTransparent(CAPTURE_DEVICE_HANDLE h,
bool &enable);
MFCAPTURE_EXPORTS HRESULT MF_GetAutoFraming(CAPTURE_DEVICE_HANDLE h,
bool &enable);
MFCAPTURE_EXPORTS HRESULT MF_SetAutoFraming(CAPTURE_DEVICE_HANDLE h,
BOOL enable);
MFCAPTURE_EXPORTS HRESULT MF_GetEyeGazeCorrection(CAPTURE_DEVICE_HANDLE h,
bool &enable);
MFCAPTURE_EXPORTS HRESULT MF_SetEyeGazeCorrection(CAPTURE_DEVICE_HANDLE h,
BOOL enable);
MFCAPTURE_EXPORTS HRESULT MF_RestoreDefaultSettings(CAPTURE_DEVICE_HANDLE h);
#ifdef __cplusplus
}
#endif

View file

@ -0,0 +1,177 @@
#include "DeviceControlChangeListener.hpp"
DeviceControlChangeListener::DeviceControlChangeListener() {}
DeviceControlChangeListener::~DeviceControlChangeListener() {}
// IUnknown methods
HRESULT __stdcall DeviceControlChangeListener::QueryInterface(REFIID iid,
void **ppv)
{
if (iid == IID_IUnknown) {
*ppv = static_cast<IUnknown *>(this);
} else if (iid == IID_IMFCameraControlNotify) {
*ppv = static_cast<IMFCameraControlNotify *>(this);
} else {
*ppv = NULL;
return E_NOINTERFACE;
}
reinterpret_cast<IUnknown *>(*ppv)->AddRef();
return S_OK;
}
ULONG __stdcall DeviceControlChangeListener::AddRef()
{
return InterlockedIncrement(&m_cRef);
}
ULONG __stdcall DeviceControlChangeListener::Release()
{
if (InterlockedDecrement(&m_cRef) == 0) {
delete this;
return 0;
}
return m_cRef;
}
HRESULT
DeviceControlChangeListener::HandleControlSet_ExtendedCameraControl(UINT32 id)
{
if (id != KSPROPERTY_CAMERACONTROL_EXTENDED_EYEGAZECORRECTION &&
id != KSPROPERTY_CAMERACONTROL_EXTENDED_BACKGROUNDSEGMENTATION &&
id != KSPROPERTY_CAMERACONTROL_EXTENDED_DIGITALWINDOW &&
id != KSPROPERTY_CAMERACONTROL_EXTENDED_DIGITALWINDOW_CONFIGCAPS &&
id != KSPROPERTY_CAMERACONTROL_EXTENDED_VIDEOHDR) {
return HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED);
}
DWORD dwStreamIndex = KSCAMERA_EXTENDEDPROP_FILTERSCOPE;
wil::com_ptr<IMFExtendedCameraControl> spExtControl = nullptr;
RETURN_IF_FAILED(m_spExtCamController->GetExtendedCameraControl(
dwStreamIndex, id, &spExtControl));
ULONGLONG Flags = spExtControl->GetFlags();
WS_CONTROL_TYPE ctrlType = WS_EFFECT_UNKNOWN;
WS_CONTROL_VALUE ctrlValue = WS_EFFECT_OFF;
if (id == KSPROPERTY_CAMERACONTROL_EXTENDED_EYEGAZECORRECTION) {
bool effect = Flags &
KSCAMERA_EXTENDEDPROP_EYEGAZECORRECTION_ON;
} else if (id ==
KSPROPERTY_CAMERACONTROL_EXTENDED_BACKGROUNDSEGMENTATION) {
bool blur = Flags &
KSCAMERA_EXTENDEDPROP_BACKGROUNDSEGMENTATION_BLUR;
bool focus =
Flags &
KSCAMERA_EXTENDEDPROP_BACKGROUNDSEGMENTATION_SHALLOWFOCUS;
bool mask = Flags &
KSCAMERA_EXTENDEDPROP_BACKGROUNDSEGMENTATION_MASK;
if (focus) {
blur = false;
}
} else if (id == KSPROPERTY_CAMERACONTROL_EXTENDED_DIGITALWINDOW) {
bool effect =
Flags &
KSCAMERA_EXTENDEDPROP_DIGITALWINDOW_AUTOFACEFRAMING;
}
return S_OK;
}
void PrintGuid(GUID guid)
{
printf("{%08lX-%04hX-%04hX-%02hhX%02hhX-%02hhX%02hhX%02hhX%02hhX%02hhX%02hhX}",
guid.Data1, guid.Data2, guid.Data3, guid.Data4[0], guid.Data4[1],
guid.Data4[2], guid.Data4[3], guid.Data4[4], guid.Data4[5],
guid.Data4[6], guid.Data4[7]);
}
void STDMETHODCALLTYPE
DeviceControlChangeListener::OnChange(_In_ REFGUID controlSet, _In_ UINT32 id)
{
auto lock = m_lock.lock();
printf("Guid = ");
PrintGuid(controlSet);
printf(" Id = %d\n", id);
if (IsEqualCLSID(controlSet, KSPROPERTYSETID_ANYCAMERACONTROL)) {
printf("KSPROPERTYSETID_ANYCAMERACONTROL\n");
} else if (IsEqualCLSID(controlSet, PROPSETID_VIDCAP_VIDEOPROCAMP)) {
printf("PROPSETID_VIDCAP_VIDEOPROCAMP\n");
} else if (IsEqualCLSID(controlSet, PROPSETID_VIDCAP_CAMERACONTROL)) {
printf("PROPSETID_VIDCAP_CAMERACONTROL\n");
} else if (IsEqualCLSID(controlSet,
KSPROPERTYSETID_ExtendedCameraControl)) {
printf("KSPROPERTYSETID_ExtendedCameraControl\n");
HandleControlSet_ExtendedCameraControl(id);
} else {
printf("Unknown control set\n");
}
}
void STDMETHODCALLTYPE
DeviceControlChangeListener::OnError(_In_ HRESULT hrStatus)
{
auto lock = m_lock.lock();
printf("%s, hrStatus = 0x%x\n", __FUNCSIG__, hrStatus);
}
HRESULT DeviceControlChangeListener::Start(
const wchar_t *devId, IMFExtendedCameraController *pExtCamController)
{
{
auto lock = m_lock.lock();
if (m_bStarted) {
return S_OK;
}
}
wil::com_ptr_nothrow<IMFCameraControlMonitor> spMonitor;
RETURN_IF_FAILED(MFCreateCameraControlMonitor(devId, this, &spMonitor));
RETURN_IF_FAILED(spMonitor->AddControlSubscription(
KSPROPERTYSETID_ANYCAMERACONTROL, 0));
RETURN_IF_FAILED(spMonitor->Start());
{
auto lock = m_lock.lock();
m_spMonitor = spMonitor;
}
m_spExtCamController = pExtCamController;
m_bStarted = true;
return S_OK;
}
HRESULT DeviceControlChangeListener::Stop()
{
auto lock = m_lock.lock();
if (!m_bStarted) {
return S_OK;
}
if (m_spMonitor != nullptr) {
m_spMonitor->RemoveControlSubscription(
KSPROPERTYSETID_ANYCAMERACONTROL, 0);
(void)m_spMonitor->Shutdown();
m_spMonitor = nullptr;
}
m_spExtCamController = nullptr;
m_bStarted = false;
return S_OK;
}

View file

@ -0,0 +1,62 @@
#pragma once
#include "framework.hpp"
#include <wil\cppwinrt.h> // must be before the first C++ WinRT header, ref:https://github.com/Microsoft/wil/wiki/Error-handling-helpers
#include <wil\result.h>
#include <wil\com.h>
#include <mfidl.h>
#include <string>
typedef enum _WS_CONTROL_TYPE {
WS_EFFECT_UNKNOWN = -1,
WS_BACKGROUND_STANDARD = 0,
WS_BACKGROUND_PORTRAIT = 1,
WS_BACKGROUND_MASK = 2,
WS_BACKGROUND_NONE = 3,
WS_AUTO_FRAMING = 4,
WS_EYE_CONTACT = 5,
} WS_CONTROL_TYPE;
typedef enum _WS_CONTROL_VALUE {
WS_EFFECT_OFF = 0,
WS_EFFECT_ON = 1,
} WS_CONTROL_VALUE;
class DeviceControlChangeListener : public IMFCameraControlNotify {
long m_cRef = 1;
wil::critical_section m_lock;
std::wstring m_wsDevId;
wil::com_ptr_nothrow<IMFCameraControlMonitor> m_spMonitor = nullptr;
wil::com_ptr_nothrow<IKsControl> m_spKsControl = nullptr;
wil::com_ptr_nothrow<IMFExtendedCameraController> m_spExtCamController =
nullptr;
void *m_cbdata = nullptr;
bool m_bStarted = false;
private:
HRESULT HandleControlSet_ExtendedCameraControl(UINT32 id);
public:
DeviceControlChangeListener();
~DeviceControlChangeListener();
// IUnknown methods
IFACEMETHODIMP_(ULONG) AddRef(void) override;
IFACEMETHODIMP_(ULONG) Release(void) override;
IFACEMETHODIMP QueryInterface(_In_ REFIID riid,
_Out_ LPVOID *ppvObject) override;
// IMFCameraControlNotify methods
void STDMETHODCALLTYPE OnChange(_In_ REFGUID controlSet,
_In_ UINT32 id);
void STDMETHODCALLTYPE OnError(_In_ HRESULT hrStatus);
HRESULT Start(const wchar_t *devId,
IMFExtendedCameraController *pExtCamController);
HRESULT Stop();
};

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,148 @@
#pragma once
#define ARGB_SEG_MASK_WORKAROUND
struct CameraInformation {
std::wstring FriendlyName;
std::wstring SymbolicLink;
};
struct StreamInformation {
UINT32 uiWidth;
UINT32 uiHeight;
UINT32 uiFpsN;
UINT32 uiFpsD;
GUID guidSubtype;
};
struct MepSetting {
std::wstring SymbolicLink;
bool Blur = false;
bool ShallowFocus = false;
bool Mask = false;
bool AutoFraming = false;
bool EyeGazeCorrection = false;
};
class PhysicalCamera : public IMFSourceReaderCallback {
static std::vector<MepSetting> s_MepSettings;
private:
long m_cRef = 1;
winrt::slim_mutex m_Lock;
wil::com_ptr_nothrow<IMFMediaSource> m_spDevSource = nullptr;
wil::com_ptr_nothrow<IMFSourceReader> m_spSourceReader = nullptr;
wil::com_ptr_nothrow<IMFDXGIDeviceManager> m_spDxgiDevManager = nullptr;
wil::com_ptr_nothrow<IMFExtendedCameraController> m_spExtController =
nullptr;
MF_VideoDataCallback m_cbVideoData = nullptr;
void *m_pUserData = nullptr;
MF_COLOR_FORMAT m_fmt = MF_COLOR_FORMAT_UNKNOWN;
UINT32 m_uiWidth = 0;
UINT32 m_uiHeight = 0;
LONG m_lDefaultStride = 0;
UINT32 m_uiSegMaskBufSize = 0;
BYTE *m_pSegMaskBuf = nullptr;
bool m_transparent = false;
#ifdef ARGB_SEG_MASK_WORKAROUND
BYTE *m_pBufferArgbOut = nullptr;
#endif
std::wstring m_wsSymbolicName;
DeviceControlChangeListener *m_pDevCtrlNotify = nullptr;
private:
HRESULT CreateSourceReader(IMFMediaSource *pSource,
IMFDXGIDeviceManager *pDxgiDevIManager,
IMFSourceReader **ppSourceReader);
HRESULT FindMatchingNativeMediaType(DWORD dwPhyStrmIndex,
UINT32 uiWidth, UINT32 uiHeight,
UINT32 uiFpsN, UINT32 uiFpsD,
IMFMediaType **ppMatchingType);
HRESULT FindMatchingNativeMediaType(DWORD dwPhyStrmIndex,
UINT32 uiWidth, UINT32 uiHeight,
LONGLONG llInterval,
IMFMediaType **ppMatchingType);
HRESULT GetMepSetting(MepSetting &setting);
HRESULT SetMepSetting(MepSetting &setting);
HRESULT SaveSettingsToDefault();
HRESULT FillSegMask(IMFSample *pSample);
HRESULT FillAlphaWithSegMask(DWORD *pData);
public:
PhysicalCamera();
~PhysicalCamera();
PhysicalCamera(const PhysicalCamera &) = delete;
PhysicalCamera &operator=(PhysicalCamera const &) = delete;
// IUnknown methods
STDMETHODIMP QueryInterface(REFIID iid, void **ppv);
STDMETHODIMP_(ULONG) AddRef();
STDMETHODIMP_(ULONG) Release();
// IMFSourceReaderCallback methods
STDMETHODIMP OnReadSample(HRESULT hrStatus, DWORD dwPhyStrmIndex,
DWORD dwStreamFlags, LONGLONG llTimestamp,
IMFSample *pSample);
STDMETHODIMP OnEvent(DWORD, IMFMediaEvent *) { return S_OK; }
STDMETHODIMP OnFlush(DWORD) { return S_OK; }
HRESULT Initialize(LPCWSTR pwszSymLink);
HRESULT Uninitialize();
HRESULT SetD3dManager(IMFDXGIDeviceManager *pD3dManager);
HRESULT Prepare();
HRESULT Start(DWORD dwPhyStrmIndex, MF_VideoDataCallback cb,
void *pUserData);
HRESULT Stop();
HRESULT GetStreamCapabilities(DWORD dwPhyStrmIndex,
std::vector<StreamInformation> &strmCaps);
void SetTransparent(bool flag) { m_transparent = flag; }
bool GetTransparent() { return m_transparent; }
// if llInterval is 0, set the camera to us the max fps
// otherwise, set camera with matching fps.
HRESULT SetOutputResolution(DWORD dwPhyStrmIndex, UINT32 uiWidth,
UINT32 uiHeight, LONGLONG llInterval,
MF_COLOR_FORMAT fmt);
HRESULT GetCurrentStreamInformation(DWORD dwPhyStrmIndex,
StreamInformation &strmInfo);
HRESULT SetBlur(bool blur, bool shallowFocus, bool mask);
HRESULT GetBlur(bool &blur, bool &shallowFocus, bool &mask);
HRESULT SetAutoFraming(bool enable);
HRESULT GetAutoFraming(bool &enable);
HRESULT SetEyeGazeCorrection(bool enable);
HRESULT GetEyeGazeCorrection(bool &enable);
HRESULT RestoreDefaultSettings();
static HRESULT CreateInstance(PhysicalCamera **ppPhysicalCamera);
static HRESULT
GetPhysicalCameras(std::vector<CameraInformation> &cameras);
};

View file

@ -0,0 +1,27 @@
#pragma once
#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
// Windows Header Files
#include <windows.h>
#include "winrt\Windows.Foundation.h"
#include "winrt\Windows.ApplicationModel.h"
#include <wil\cppwinrt.h> // must be before the first C++ WinRT header, ref:https://github.com/Microsoft/wil/wiki/Error-handling-helpers
#include <wil\result.h>
#include <wil\com.h>
#include <Ks.h>
#include <ksproxy.h>
#include <ksmedia.h>
#include <mfapi.h>
#include <mfidl.h>
#include <mfobjects.h>
#include <mferror.h>
#include <mfreadwrite.h>
#include <d3d11.h>
#include <mfidl.h>
#include <cfgmgr32.h>
#include <initguid.h>

View file

@ -0,0 +1,224 @@
#include "mfcapture.hpp"
#include "DeviceControlChangeListener.hpp"
#include "PhysicalCamera.hpp"
MFCAPTURE_EXPORTS HRESULT MF_EnumerateCameras(MF_EnumerateCameraCallback cb,
void *pUserData)
{
std::vector<CameraInformation> camlist;
RETURN_IF_FAILED(PhysicalCamera::GetPhysicalCameras(camlist));
for (auto &cam : camlist) {
if (cb) {
cb(cam.FriendlyName.c_str(), cam.SymbolicLink.c_str(),
pUserData);
}
}
return S_OK;
}
MFCAPTURE_EXPORTS CAPTURE_DEVICE_HANDLE MF_Create(const wchar_t *DevId)
{
wil::com_ptr_nothrow<PhysicalCamera> spCapture = nullptr;
HRESULT hr = PhysicalCamera::CreateInstance(&spCapture);
if (FAILED(hr)) {
return NULL;
}
hr = spCapture->Initialize(DevId);
if (FAILED(hr)) {
return NULL;
}
return spCapture.detach();
}
MFCAPTURE_EXPORTS void MF_Destroy(CAPTURE_DEVICE_HANDLE h)
{
PhysicalCamera *p = (PhysicalCamera *)h;
if (p) {
p->Release();
}
}
MFCAPTURE_EXPORTS HRESULT MF_Prepare(CAPTURE_DEVICE_HANDLE h)
{
PhysicalCamera *p = (PhysicalCamera *)h;
if (!p) {
return E_INVALIDARG;
}
return p->Prepare();
}
MFCAPTURE_EXPORTS HRESULT MF_EnumerateStreamCapabilities(
CAPTURE_DEVICE_HANDLE h, MF_EnumerateStreamCapabilitiesCallback cb,
void *pUserData)
{
PhysicalCamera *p = (PhysicalCamera *)h;
if (!p) {
return E_INVALIDARG;
}
std::vector<StreamInformation> caplist;
HRESULT hr = p->GetStreamCapabilities(0, caplist);
if (FAILED(hr)) {
return hr;
}
for (auto &cap : caplist) {
if (cb) {
cb(cap.uiWidth, cap.uiHeight, cap.uiFpsN, cap.uiFpsD,
pUserData);
}
}
return S_OK;
}
MFCAPTURE_EXPORTS HRESULT MF_SetOutputResolution(CAPTURE_DEVICE_HANDLE h,
UINT32 uiWidth,
UINT32 uiHeight,
LONGLONG llInterval,
MF_COLOR_FORMAT fmt)
{
PhysicalCamera *p = (PhysicalCamera *)h;
if (!p) {
return E_INVALIDARG;
}
return p->SetOutputResolution(0, uiWidth, uiHeight, llInterval, fmt);
}
MFCAPTURE_EXPORTS HRESULT MF_GetOutputResolution(CAPTURE_DEVICE_HANDLE h,
UINT32 *uiWidth,
UINT32 *uiHeight,
UINT32 *uiFpsN, UINT32 *uiFpsD)
{
PhysicalCamera *p = (PhysicalCamera *)h;
if (!p) {
return E_INVALIDARG;
}
StreamInformation info;
RETURN_IF_FAILED(p->GetCurrentStreamInformation(0, info));
if (uiWidth && uiHeight && uiFpsN && uiFpsD) {
*uiWidth = info.uiWidth;
*uiHeight = info.uiHeight;
*uiFpsN = info.uiFpsN;
*uiFpsD = info.uiFpsD;
}
return S_OK;
}
MFCAPTURE_EXPORTS HRESULT MF_Start(CAPTURE_DEVICE_HANDLE h,
MF_VideoDataCallback cb, void *pUserData)
{
PhysicalCamera *p = (PhysicalCamera *)h;
if (!p) {
return E_INVALIDARG;
}
return p->Start(0, cb, pUserData);
}
MFCAPTURE_EXPORTS HRESULT MF_Stop(CAPTURE_DEVICE_HANDLE h)
{
PhysicalCamera *p = (PhysicalCamera *)h;
if (!p) {
return E_INVALIDARG;
}
return p->Stop();
}
MFCAPTURE_EXPORTS HRESULT MF_GetBlur(CAPTURE_DEVICE_HANDLE h, bool &blur,
bool &shallowFocus, bool &mask)
{
PhysicalCamera *p = (PhysicalCamera *)h;
if (!p) {
return E_INVALIDARG;
}
return p->GetBlur(blur, shallowFocus, mask);
}
MFCAPTURE_EXPORTS HRESULT MF_SetBlur(CAPTURE_DEVICE_HANDLE h, BOOL blur,
BOOL shallowFocus, BOOL mask)
{
PhysicalCamera *p = (PhysicalCamera *)h;
if (!p) {
return E_INVALIDARG;
}
p->SetTransparent(mask);
return p->SetBlur(blur, shallowFocus, mask);
}
MFCAPTURE_EXPORTS HRESULT MF_GetTransparent(CAPTURE_DEVICE_HANDLE h,
bool &enable)
{
PhysicalCamera *p = (PhysicalCamera *)h;
if (!p) {
return E_INVALIDARG;
}
enable = p->GetTransparent();
return S_OK;
}
MFCAPTURE_EXPORTS HRESULT MF_GetAutoFraming(CAPTURE_DEVICE_HANDLE h,
bool &enable)
{
PhysicalCamera *p = (PhysicalCamera *)h;
if (!p) {
return E_INVALIDARG;
}
return p->GetAutoFraming(enable);
}
MFCAPTURE_EXPORTS HRESULT MF_SetAutoFraming(CAPTURE_DEVICE_HANDLE h,
BOOL enable)
{
PhysicalCamera *p = (PhysicalCamera *)h;
if (!p) {
return E_INVALIDARG;
}
return p->SetAutoFraming(enable);
}
MFCAPTURE_EXPORTS HRESULT MF_GetEyeGazeCorrection(CAPTURE_DEVICE_HANDLE h,
bool &enable)
{
PhysicalCamera *p = (PhysicalCamera *)h;
if (!p) {
return E_INVALIDARG;
}
return p->GetEyeGazeCorrection(enable);
}
MFCAPTURE_EXPORTS HRESULT MF_SetEyeGazeCorrection(CAPTURE_DEVICE_HANDLE h,
BOOL enable)
{
PhysicalCamera *p = (PhysicalCamera *)h;
if (!p) {
return E_INVALIDARG;
}
return p->SetEyeGazeCorrection(enable);
}
MFCAPTURE_EXPORTS HRESULT MF_RestoreDefaultSettings(CAPTURE_DEVICE_HANDLE h)
{
PhysicalCamera *p = (PhysicalCamera *)h;
if (!p) {
return E_INVALIDARG;
}
return p->RestoreDefaultSettings();
}

View file

@ -0,0 +1,141 @@
// Microsoft Visual C++ generated resource script.
//
#include "resource.hpp"
#define APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 2 resource.
//
#include "winres.h"
/////////////////////////////////////////////////////////////////////////////
#undef APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
// English (United States) resources
#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
#pragma code_page(1252)
#ifdef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// TEXTINCLUDE
//
1 TEXTINCLUDE
BEGIN
"resource.h\0"
END
2 TEXTINCLUDE
BEGIN
"#include ""winres.h""\r\n"
"\0"
END
3 TEXTINCLUDE
BEGIN
"\r\n"
"\0"
END
#endif // APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// Dialog
//
IDD_DIALOG_EFFECT_CONTROL DIALOGEX 0, 0, 235, 144
STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "Effect Control"
FONT 8, "MS Shell Dlg", 400, 0, 0x1
BEGIN
DEFPUSHBUTTON "OK",IDOK,92,123,50,14
CONTROL "Auto Framing",IDC_CHECK_AUTOFRAMING,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,34,65,59,10
CONTROL "Eye Gaze Correction",IDC_CHECK_EYEGAZE,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,34,82,81,10
CONTROL "Portrait Blur",IDC_RADIO_BLUR_PORTRAIT,"Button",BS_AUTORADIOBUTTON,34,38,54,10
CONTROL "Standard Blur",IDC_RADIO_BLUR_STANDARD,"Button",BS_AUTORADIOBUTTON,99,38,59,10
GROUPBOX "Blur",IDC_STATIC,18,20,199,40
CONTROL "None",IDC_RADIO_NOBLUR,"Button",BS_AUTORADIOBUTTON,169,38,33,10
CONTROL "Background Transparent",IDC_CHECK_BK,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,34,99,95,10
END
/////////////////////////////////////////////////////////////////////////////
//
// DESIGNINFO
//
#ifdef APSTUDIO_INVOKED
GUIDELINES DESIGNINFO
BEGIN
IDD_DIALOG_EFFECT_CONTROL, DIALOG
BEGIN
LEFTMARGIN, 7
RIGHTMARGIN, 230
TOPMARGIN, 7
BOTTOMMARGIN, 137
END
END
#endif // APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// AFX_DIALOG_LAYOUT
//
IDD_DIALOG_EFFECT_CONTROL AFX_DIALOG_LAYOUT
BEGIN
0
END
/////////////////////////////////////////////////////////////////////////////
//
// Version
//
VS_VERSION_INFO VERSIONINFO
FILEVERSION 30,0,1,0
BEGIN
BLOCK "StringFileInfo"
BEGIN
BLOCK "040904B0"
BEGIN
VALUE "CompanyName", "Intel Corporation"
VALUE "FileDescription", "OBS Video Capture module"
VALUE "FileVersion", "30.0.1"
VALUE "ProductName", "OBS Studio"
VALUE "ProductVersion", "30.0.1"
VALUE "LegalCopyright", "Copyright (C) 2023, Intel Corporation"
VALUE "InternalName", "win-mf"
VALUE "OriginalFilename", "win-mf"
END
END
BLOCK "VarFileInfo"
BEGIN
VALUE "Translation", 0x409,1200
END
END
#endif // English (United States) resources
/////////////////////////////////////////////////////////////////////////////
#ifndef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 3 resource.
//
/////////////////////////////////////////////////////////////////////////////
#endif // not APSTUDIO_INVOKED

View file

@ -0,0 +1,23 @@
// {{NO_DEPENDENCIES}}
// Microsoft Visual C++ generated include file.
// Used by libmfcapture.rc
//
#define IDD_DIALOG1 101
#define IDD_DIALOG_EFFECT_CONTROL 101
#define IDC_CHECK_BK 1002
#define IDC_CHECK_AUTOFRAMING 1003
#define IDC_CHECK_EYEGAZE 1004
#define IDC_RADIO_BLUR_PORTRAIT 1005
#define IDC_RADIO_BLUR_STANDARD 1006
#define IDC_RADIO_NOBLUR 1007
// Next default values for new objects
//
#ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NEXT_RESOURCE_VALUE 103
#define _APS_NEXT_COMMAND_VALUE 40001
#define _APS_NEXT_CONTROL_VALUE 1008
#define _APS_NEXT_SYMED_VALUE 101
#endif
#endif

View file

@ -0,0 +1,24 @@
/* mf-plugin.cpp */
#include <obs-module.h>
#include <strsafe.h>
#include <strmif.h>
#include "plugin-macros.generated.h"
OBS_DECLARE_MODULE()
OBS_MODULE_USE_DEFAULT_LOCALE(PLUGIN_NAME, "en-US")
extern void RegisterMediaFoundationSource();
bool obs_module_load(void)
{
RegisterMediaFoundationSource();
obs_data_t *obs_settings = obs_data_create();
obs_apply_private_data(obs_settings);
obs_data_release(obs_settings);
return true;
}
void obs_module_unload()
{
blog(LOG_INFO, "plugin unloaded");
}

View file

@ -0,0 +1,28 @@
/*
Plugin Name
Copyright (C) <Year> <Developer> <Email Address>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program. If not, see <https://www.gnu.org/licenses/>
*/
#ifndef PLUGINNAME_H
#define PLUGINNAME_H
#define PLUGIN_NAME "obs-mf-source"
#define PLUGIN_VERSION "2023.1.0.0"
#define blog(level, msg, ...) \
blog(level, "[" PLUGIN_NAME "] " msg, ##__VA_ARGS__)
#endif // PLUGINNAME_H

View file

@ -0,0 +1,27 @@
/*
Plugin Name
Copyright (C) <Year> <Developer> <Email Address>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program. If not, see <https://www.gnu.org/licenses/>
*/
#ifndef PLUGINNAME_H
#define PLUGINNAME_H
#define PLUGIN_NAME "@CMAKE_PROJECT_NAME@"
#define PLUGIN_VERSION "@CMAKE_PROJECT_VERSION@"
#define blog(level, msg, ...) blog(level, "[" PLUGIN_NAME "] " msg, ##__VA_ARGS__)
#endif // PLUGINNAME_H

1736
plugins/win-mf/win-mf.cpp Normal file

File diff suppressed because it is too large Load diff