mirror of
https://github.com/spice2x/spice2x.github.io.git
synced 2026-08-02 06:40:42 -07:00
88a210e82e
## Link to GitHub Issue or related Pull Request, if one exists #201 ## Description of change - Adds MJPEG camera support using Media Foundation decoding. - Moves camera capture to asynchronous Source Reader callbacks. - Supports native NV12 and YUY2 capture, preferring target-sized native formats over MJPEG when possible. - Improves capture and rendering performance through callback-paced reads, bulk frame uploads, optimized row-based flips, and lazy allocation of flip textures. - Makes runtime media-type changes interrupt pending reads and safely flush and reconfigure the Source Reader. - Improves automatic mode selection based on aspect ratio, proximity to 1280x720, frame rate, and capture format. - Hardens camera shutdown, flush handling, media-type changes, and repeated capture failures. ## Testing Tested with two cameras in tdj
132 lines
4.9 KiB
C++
132 lines
4.9 KiB
C++
#include "mf_wrappers.h"
|
|
#include "util/libutils.h"
|
|
#include "util/logging.h"
|
|
|
|
namespace games::iidx {
|
|
|
|
static bool INITIALIZED = false;
|
|
|
|
static HMODULE mf_dll = nullptr;
|
|
static HMODULE mfreadwrite_dll = nullptr;
|
|
static HMODULE mfplat_dll = nullptr;
|
|
|
|
typedef HRESULT (__stdcall * MFCreateAttributes_t)(
|
|
_Out_ IMFAttributes** ppMFAttributes,
|
|
_In_ UINT32 cInitialSize
|
|
);
|
|
|
|
typedef HRESULT (__stdcall * MFCreateMediaType_t)(
|
|
_Out_ IMFMediaType** ppMFType
|
|
);
|
|
|
|
typedef HRESULT (__stdcall * MFEnumDeviceSources_t)(
|
|
_In_ IMFAttributes* pAttributes,
|
|
_Outptr_result_buffer_(*pcSourceActivate) IMFActivate*** pppSourceActivate,
|
|
_Out_ UINT32* pcSourceActivate
|
|
);
|
|
|
|
typedef HRESULT (__stdcall * MFCreateSourceReaderFromMediaSource_t)(
|
|
_In_ IMFMediaSource *pMediaSource,
|
|
_In_opt_ IMFAttributes *pAttributes,
|
|
_Out_ IMFSourceReader **ppSourceReader
|
|
);
|
|
|
|
typedef HRESULT (__stdcall * MFGetService_t)(
|
|
IUnknown* punkObject,
|
|
REFGUID guidService,
|
|
REFIID riid,
|
|
_Outptr_ LPVOID* ppvObject
|
|
);
|
|
|
|
static MFCreateAttributes_t MFCreateAttributes = nullptr;
|
|
static MFCreateMediaType_t MFCreateMediaType = nullptr;
|
|
static MFEnumDeviceSources_t MFEnumDeviceSources = nullptr;
|
|
static MFCreateSourceReaderFromMediaSource_t MFCreateSourceReaderFromMediaSource = nullptr;
|
|
static MFGetService_t MFGetService = nullptr;
|
|
|
|
void init_mf_library() {
|
|
|
|
// why was all of this needed?
|
|
//
|
|
// when iidx camhook was initially implemented, we linked to mf.lib, mfreadwrite.lib, and mfplat.lib
|
|
// this made Unity-based really unhappy, causing them to skip over the logic that loads mf library
|
|
// causing videos to not play ("Initializing Microsoft Media Foundation failed." in the cmd prompt)
|
|
//
|
|
// as a result, the static linking to mf libs were removed, and we are now doing the mess that is this file
|
|
|
|
if (INITIALIZED) {
|
|
return;
|
|
}
|
|
INITIALIZED = true;
|
|
|
|
log_misc("mf_wrappers", "creating delay-loaded wrappers for MF routines - BEGIN");
|
|
|
|
mf_dll = libutils::load_library("mf.dll", true);
|
|
mfreadwrite_dll = libutils::load_library("mfreadwrite.dll", true);
|
|
mfplat_dll = libutils::load_library("mfplat.dll", true);
|
|
|
|
MFCreateAttributes = (MFCreateAttributes_t)
|
|
libutils::get_proc(mfplat_dll, "MFCreateAttributes");
|
|
if (!MFCreateAttributes) {
|
|
log_fatal("mf_wrappers", "MFCreateAttributes failed to hook");
|
|
}
|
|
|
|
MFCreateMediaType = (MFCreateMediaType_t)
|
|
libutils::get_proc(mfplat_dll, "MFCreateMediaType");
|
|
if (!MFCreateMediaType) {
|
|
log_fatal("mf_wrappers", "MFCreateMediaType failed to hook");
|
|
}
|
|
|
|
MFEnumDeviceSources = (MFEnumDeviceSources_t)
|
|
libutils::get_proc(mf_dll, "MFEnumDeviceSources");
|
|
if (!MFEnumDeviceSources) {
|
|
log_fatal("mf_wrappers", "MFEnumDeviceSources failed to hook");
|
|
}
|
|
|
|
MFCreateSourceReaderFromMediaSource = (MFCreateSourceReaderFromMediaSource_t)
|
|
libutils::get_proc(mfreadwrite_dll, "MFCreateSourceReaderFromMediaSource");
|
|
if (!MFCreateSourceReaderFromMediaSource) {
|
|
log_fatal("mf_wrappers", "MFCreateSourceReaderFromMediaSource failed to hook");
|
|
}
|
|
|
|
MFGetService = (MFGetService_t)libutils::get_proc(mf_dll, "MFGetService");
|
|
if (!MFGetService) {
|
|
log_fatal("mf_wrappers", "MFGetService failed to hook");
|
|
}
|
|
|
|
log_misc("mf_wrappers", "creating delay-loaded wrappers for MF routines - DONE");
|
|
}
|
|
|
|
HRESULT WrappedMFCreateAttributes (
|
|
_Out_ IMFAttributes** ppMFAttributes,
|
|
_In_ UINT32 cInitialSize) {
|
|
return MFCreateAttributes(ppMFAttributes, cInitialSize);
|
|
}
|
|
|
|
HRESULT WrappedMFCreateMediaType (
|
|
_Out_ IMFMediaType** ppMFType) {
|
|
return MFCreateMediaType(ppMFType);
|
|
}
|
|
|
|
HRESULT WrappedMFEnumDeviceSources (
|
|
_In_ IMFAttributes* pAttributes,
|
|
_Outptr_result_buffer_(*pcSourceActivate) IMFActivate*** pppSourceActivate,
|
|
_Out_ UINT32* pcSourceActivate) {
|
|
return MFEnumDeviceSources(pAttributes, pppSourceActivate, pcSourceActivate);
|
|
}
|
|
|
|
HRESULT WrappedMFCreateSourceReaderFromMediaSource (
|
|
_In_ IMFMediaSource *pMediaSource,
|
|
_In_opt_ IMFAttributes *pAttributes,
|
|
_Out_ IMFSourceReader **ppSourceReader) {
|
|
return MFCreateSourceReaderFromMediaSource(pMediaSource, pAttributes, ppSourceReader);
|
|
}
|
|
|
|
HRESULT WrappedMFGetService (
|
|
IUnknown* punkObject,
|
|
REFGUID guidService,
|
|
REFIID riid,
|
|
_Outptr_ LPVOID* ppvObject) {
|
|
return MFGetService(punkObject, guidService, riid, ppvObject);
|
|
}
|
|
} |