Add camera support for windows.
This commit is contained in:
parent
6d8ddb7a71
commit
034a257baf
12 changed files with 1134 additions and 20 deletions
|
@ -1864,6 +1864,9 @@ set(WindowsFiles
|
|||
Windows/GEDebugger/GEDebugger.h
|
||||
Windows/GEDebugger/TabDisplayLists.h
|
||||
Windows/GEDebugger/TabVertices.h
|
||||
Windows/BufferLock.h
|
||||
Windows/CaptureDevice.cpp
|
||||
Windows/CaptureDevice.h
|
||||
Windows/DinputDevice.cpp
|
||||
Windows/DinputDevice.h
|
||||
Windows/DSoundStream.cpp
|
||||
|
@ -1917,7 +1920,7 @@ set(WindowsFiles
|
|||
list(APPEND LinkCommon ${CoreLibName} ${CMAKE_THREAD_LIBS_INIT})
|
||||
|
||||
if(WIN32)
|
||||
list(APPEND LinkCommon kernel32 user32 gdi32 shell32 comctl32 dsound xinput d3d9 winmm dinput8 ole32 winspool ksuser)
|
||||
list(APPEND LinkCommon kernel32 user32 gdi32 shell32 comctl32 dsound xinput d3d9 winmm dinput8 ole32 winspool ksuser mf mfplat mfreadwrite mfuuid shlwapi)
|
||||
#setup_target_project(${TargetBin} Windows)
|
||||
list(APPEND NativeAppSource ${WindowsFiles})
|
||||
endif()
|
||||
|
|
|
@ -706,6 +706,7 @@ static ConfigSetting graphicsSettings[] = {
|
|||
ConfigSetting("VulkanDevice", &g_Config.sVulkanDevice, "", true, false),
|
||||
#ifdef _WIN32
|
||||
ConfigSetting("D3D11Device", &g_Config.sD3D11Device, "", true, false),
|
||||
ConfigSetting("WinCameraDevice", &g_Config.sWinCameraDevice, "", true, false),
|
||||
#endif
|
||||
ConfigSetting("VendorBugChecksEnabled", &g_Config.bVendorBugChecksEnabled, true, false, false),
|
||||
ReportedConfigSetting("RenderingMode", &g_Config.iRenderingMode, 1, true, true),
|
||||
|
|
|
@ -128,6 +128,7 @@ public:
|
|||
// If not set, will use the "best" device.
|
||||
std::string sVulkanDevice;
|
||||
std::string sD3D11Device; // Windows only
|
||||
std::string sWinCameraDevice; // Windows only
|
||||
|
||||
bool bSoftwareRendering;
|
||||
bool bHardwareTransform; // only used in the GLES backend
|
||||
|
|
|
@ -25,6 +25,12 @@
|
|||
#include "Core/HLE/sceUsbCam.h"
|
||||
#include "Core/MemMapHelpers.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#include "Windows/CaptureDevice.h"
|
||||
#undef min
|
||||
#endif
|
||||
|
||||
|
||||
PspUsbCamSetupMicParam micParam;
|
||||
PspUsbCamSetupVideoParam videoParam;
|
||||
|
||||
|
@ -32,6 +38,7 @@ unsigned int videoBufferLength = 0;
|
|||
unsigned int nextVideoFrame = 0;
|
||||
uint8_t *videoBuffer;
|
||||
std::mutex videoBufferMutex;
|
||||
bool isShutDown = false;
|
||||
|
||||
enum {
|
||||
VIDEO_BUFFER_SIZE = 40 * 1000,
|
||||
|
@ -39,9 +46,17 @@ enum {
|
|||
|
||||
void __UsbCamInit() {
|
||||
videoBuffer = new uint8_t[VIDEO_BUFFER_SIZE];
|
||||
isShutDown = false;
|
||||
}
|
||||
|
||||
void __UsbCamShutdown() {
|
||||
#ifdef _WIN32
|
||||
if (winCamera) {
|
||||
winCamera->sendMessage({ CAPTUREDEVIDE_COMMAND::SHUTDOWN, nullptr });
|
||||
}
|
||||
#endif
|
||||
isShutDown = true;
|
||||
|
||||
delete[] videoBuffer;
|
||||
videoBuffer = nullptr;
|
||||
}
|
||||
|
@ -97,13 +112,31 @@ static int sceUsbCamSetupVideo(u32 paramAddr, u32 workareaAddr, int wasize) {
|
|||
|
||||
static int sceUsbCamStartVideo() {
|
||||
INFO_LOG(HLE, "UNIMPL sceUsbCamStartVideo");
|
||||
#ifdef _WIN32
|
||||
if (winCamera) {
|
||||
if (winCamera->isShutDown()) {
|
||||
delete winCamera;
|
||||
winCamera = new WindowsCaptureDevice(CAPTUREDEVIDE_TYPE::VIDEO);
|
||||
winCamera->sendMessage({ CAPTUREDEVIDE_COMMAND::INITIALIZE, nullptr });
|
||||
}
|
||||
|
||||
winCamera->sendMessage({ CAPTUREDEVIDE_COMMAND::START, nullptr });
|
||||
}
|
||||
|
||||
#else
|
||||
System_SendMessage("camera_command", "startVideo");
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sceUsbCamStopVideo() {
|
||||
INFO_LOG(HLE, "UNIMPL sceUsbCamStopVideo");
|
||||
#ifdef _WIN32
|
||||
if (winCamera)
|
||||
winCamera->sendMessage({ CAPTUREDEVIDE_COMMAND::STOP, nullptr });
|
||||
#else
|
||||
System_SendMessage("camera_command", "stopVideo");
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -114,7 +147,6 @@ static int sceUsbCamAutoImageReverseSW(int rev) {
|
|||
|
||||
static int sceUsbCamReadVideoFrameBlocking(u32 bufAddr, u32 size) {
|
||||
std::lock_guard<std::mutex> lock(videoBufferMutex);
|
||||
|
||||
u32 transferSize = std::min(videoBufferLength, size);
|
||||
if (Memory::IsValidRange(bufAddr, size)) {
|
||||
Memory::Memcpy(bufAddr, videoBuffer, transferSize);
|
||||
|
@ -203,6 +235,8 @@ void Register_sceUsbCam()
|
|||
|
||||
void Camera::pushCameraImage(long long length, unsigned char* image) {
|
||||
std::lock_guard<std::mutex> lock(videoBufferMutex);
|
||||
if (isShutDown)
|
||||
return;
|
||||
memset(videoBuffer, 0, VIDEO_BUFFER_SIZE);
|
||||
if (length > VIDEO_BUFFER_SIZE) {
|
||||
videoBufferLength = 0;
|
||||
|
|
|
@ -70,6 +70,11 @@
|
|||
#include "Windows/W32Util/ShellUtil.h"
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
#include "Windows/CaptureDevice.h"
|
||||
#endif
|
||||
|
||||
|
||||
GameSettingsScreen::GameSettingsScreen(std::string gamePath, std::string gameID, bool editThenRestore)
|
||||
: UIDialogScreenWithGameBackground(gamePath), gameID_(gameID), enableReports_(false), editThenRestore_(editThenRestore) {
|
||||
lastVertical_ = UseVerticalLayout();
|
||||
|
@ -262,6 +267,14 @@ void GameSettingsScreen::CreateViews() {
|
|||
softwareGPU->SetEnabled(false);
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
if (winCamera && winCamera->getDeviceList().size() >= 1) {
|
||||
graphicsSettings->Add(new ItemHeader(gr->T("Camera")));
|
||||
PopupMultiChoiceDynamic *cameraChoice = graphicsSettings->Add(new PopupMultiChoiceDynamic(&g_Config.sWinCameraDevice, gr->T("Camera Device"), winCamera->getDeviceList(), nullptr, screenManager()));
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
graphicsSettings->Add(new ItemHeader(gr->T("Frame Rate Control")));
|
||||
static const char *frameSkip[] = {"Off", "1", "2", "3", "4", "5", "6", "7", "8"};
|
||||
graphicsSettings->Add(new PopupMultiChoice(&g_Config.iFrameSkip, gr->T("Frame Skipping"), frameSkip, 0, ARRAY_SIZE(frameSkip), gr->GetName(), screenManager()));
|
||||
|
|
|
@ -37,6 +37,7 @@
|
|||
#if defined(_WIN32)
|
||||
#include "Windows/WindowsAudio.h"
|
||||
#include "Windows/MainWindow.h"
|
||||
#include "Windows/CaptureDevice.h"
|
||||
#endif
|
||||
|
||||
#include "base/display.h"
|
||||
|
@ -67,6 +68,7 @@
|
|||
#include "Common/LogManager.h"
|
||||
#include "Common/MemArena.h"
|
||||
#include "Common/GraphicsContext.h"
|
||||
#include "Common/OSVersion.h"
|
||||
#include "Core/Config.h"
|
||||
#include "Core/ConfigValues.h"
|
||||
#include "Core/Core.h"
|
||||
|
@ -855,6 +857,13 @@ bool NativeInitGraphics(GraphicsContext *graphicsContext) {
|
|||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
if (IsVistaOrHigher()) {
|
||||
winCamera = new WindowsCaptureDevice(CAPTUREDEVIDE_TYPE::VIDEO);
|
||||
winCamera->sendMessage({ CAPTUREDEVIDE_COMMAND::INITIALIZE, nullptr });
|
||||
}
|
||||
#endif
|
||||
|
||||
g_gameInfoCache = new GameInfoCache();
|
||||
|
||||
if (gpu)
|
||||
|
@ -879,6 +888,11 @@ void NativeShutdownGraphics() {
|
|||
winAudioBackend = nullptr;
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
delete winCamera;
|
||||
winCamera = nullptr;
|
||||
#endif
|
||||
|
||||
ShutdownWebServer();
|
||||
UIBackgroundShutdown();
|
||||
|
||||
|
|
|
@ -207,7 +207,7 @@
|
|||
</PrecompiledHeader>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<PreprocessorDefinitions>_CRTDBG_MAP_ALLOC;USING_WIN_UI;_CRT_SECURE_NO_WARNINGS;_ARCH_32=1;WIN32;_DEBUG;_LIB;_UNICODE;UNICODE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<AdditionalIncludeDirectories>../common;..;../ext/native;../ext/glew;../ext/snappy;../ext/zlib;../ext/native/ext</AdditionalIncludeDirectories>
|
||||
<AdditionalIncludeDirectories>..\ffmpeg\WindowsInclude;..\ffmpeg\Windows\x86_64\include;../common;..;../ext/native;../ext/glew;../ext/snappy;../ext/zlib;../ext/native/ext</AdditionalIncludeDirectories>
|
||||
<MultiProcessorCompilation>true</MultiProcessorCompilation>
|
||||
<MinimalRebuild>false</MinimalRebuild>
|
||||
<RuntimeTypeInfo>false</RuntimeTypeInfo>
|
||||
|
@ -231,7 +231,7 @@
|
|||
</PrecompiledHeader>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<PreprocessorDefinitions>_CRTDBG_MAP_ALLOC;USING_WIN_UI;_CRT_SECURE_NO_WARNINGS;_ARCH_64=1;WIN32;_DEBUG;_LIB;_UNICODE;UNICODE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<AdditionalIncludeDirectories>../common;..;../ext/native;../ext/glew;../ext/snappy;../ext/zlib;../ext/native/ext</AdditionalIncludeDirectories>
|
||||
<AdditionalIncludeDirectories>..\ffmpeg\WindowsInclude;..\ffmpeg\Windows\x86_64\include;../common;..;../ext/native;../ext/glew;../ext/snappy;../ext/zlib;../ext/native/ext</AdditionalIncludeDirectories>
|
||||
<MultiProcessorCompilation>true</MultiProcessorCompilation>
|
||||
<MinimalRebuild>false</MinimalRebuild>
|
||||
<RuntimeTypeInfo>false</RuntimeTypeInfo>
|
||||
|
@ -281,7 +281,7 @@
|
|||
</PrecompiledHeader>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<PreprocessorDefinitions>_CRTDBG_MAP_ALLOC;USING_WIN_UI;_CRT_SECURE_NO_WARNINGS;_ARCH_32=1;WIN32;_DEBUG;_LIB;_UNICODE;UNICODE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<AdditionalIncludeDirectories>../common;..;../ext/native;../ext/glew;../ext/snappy;../ext/zlib;../ext/native/ext</AdditionalIncludeDirectories>
|
||||
<AdditionalIncludeDirectories>..\ffmpeg\WindowsInclude;..\ffmpeg\Windows\x86_64\include;../common;..;../ext/native;../ext/glew;../ext/snappy;../ext/zlib;../ext/native/ext</AdditionalIncludeDirectories>
|
||||
<MultiProcessorCompilation>true</MultiProcessorCompilation>
|
||||
<MinimalRebuild>false</MinimalRebuild>
|
||||
<RuntimeTypeInfo>false</RuntimeTypeInfo>
|
||||
|
@ -310,7 +310,7 @@
|
|||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<PreprocessorDefinitions>USING_WIN_UI;_CRT_SECURE_NO_WARNINGS;_ARCH_32=1;WIN32;NDEBUG;_LIB;_UNICODE;UNICODE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<AdditionalIncludeDirectories>../common;..;../ext/native;../ext/glew;../ext/snappy;../ext/zlib;../ext/native/ext</AdditionalIncludeDirectories>
|
||||
<AdditionalIncludeDirectories>..\ffmpeg\WindowsInclude;..\ffmpeg\Windows\x86_64\include;../common;..;../ext/native;../ext/glew;../ext/snappy;../ext/zlib;../ext/native/ext</AdditionalIncludeDirectories>
|
||||
<BufferSecurityCheck>false</BufferSecurityCheck>
|
||||
<FavorSizeOrSpeed>Size</FavorSizeOrSpeed>
|
||||
<MultiProcessorCompilation>true</MultiProcessorCompilation>
|
||||
|
@ -339,7 +339,7 @@
|
|||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<PreprocessorDefinitions>USING_WIN_UI;_CRT_SECURE_NO_WARNINGS;_ARCH_64=1;WIN32;NDEBUG;_LIB;_UNICODE;UNICODE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<AdditionalIncludeDirectories>../common;..;../ext/native;../ext/glew;../ext/snappy;../ext/zlib;../ext/native/ext</AdditionalIncludeDirectories>
|
||||
<AdditionalIncludeDirectories>..\ffmpeg\WindowsInclude;..\ffmpeg\Windows\x86_64\include;../common;..;../ext/native;../ext/glew;../ext/snappy;../ext/zlib;../ext/native/ext</AdditionalIncludeDirectories>
|
||||
<BufferSecurityCheck>false</BufferSecurityCheck>
|
||||
<MultiProcessorCompilation>true</MultiProcessorCompilation>
|
||||
<RuntimeTypeInfo>false</RuntimeTypeInfo>
|
||||
|
@ -401,7 +401,7 @@
|
|||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<PreprocessorDefinitions>USING_WIN_UI;_CRT_SECURE_NO_WARNINGS;_ARCH_32=1;WIN32;NDEBUG;_LIB;_UNICODE;UNICODE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<AdditionalIncludeDirectories>../common;..;../ext/native;../ext/glew;../ext/snappy;../ext/zlib;../ext/native/ext</AdditionalIncludeDirectories>
|
||||
<AdditionalIncludeDirectories>..\ffmpeg\WindowsInclude;..\ffmpeg\Windows\x86_64\include;../common;..;../ext/native;../ext/glew;../ext/snappy;../ext/zlib;../ext/native/ext</AdditionalIncludeDirectories>
|
||||
<BufferSecurityCheck>false</BufferSecurityCheck>
|
||||
<MultiProcessorCompilation>true</MultiProcessorCompilation>
|
||||
<RuntimeTypeInfo>false</RuntimeTypeInfo>
|
||||
|
|
123
Windows/BufferLock.h
Normal file
123
Windows/BufferLock.h
Normal file
|
@ -0,0 +1,123 @@
|
|||
//////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
|
||||
// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
|
||||
// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
|
||||
// PARTICULAR PURPOSE.
|
||||
//
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
|
||||
#pragma once
|
||||
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// VideoBufferLock class
|
||||
//
|
||||
// Locks a video buffer that might or might not support IMF2DBuffer.
|
||||
//
|
||||
//-------------------------------------------------------------------
|
||||
|
||||
class VideoBufferLock
|
||||
{
|
||||
public:
|
||||
VideoBufferLock(IMFMediaBuffer *pBuffer) : m_p2DBuffer(NULL), m_bLocked(FALSE)
|
||||
{
|
||||
m_pBuffer = pBuffer;
|
||||
m_pBuffer->AddRef();
|
||||
|
||||
// Query for the 2-D buffer interface. OK if this fails.
|
||||
(void)m_pBuffer->QueryInterface(IID_PPV_ARGS(&m_p2DBuffer));
|
||||
}
|
||||
|
||||
~VideoBufferLock()
|
||||
{
|
||||
UnlockBuffer();
|
||||
SafeRelease(&m_pBuffer);
|
||||
SafeRelease(&m_p2DBuffer);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// LockBuffer
|
||||
//
|
||||
// Locks the buffer. Returns a pointer to scan line 0 and returns the stride.
|
||||
//
|
||||
// The caller must provide the default stride as an input parameter, in case
|
||||
// the buffer does not expose IMF2DBuffer. You can calculate the default stride
|
||||
// from the media type.
|
||||
//-------------------------------------------------------------------
|
||||
|
||||
HRESULT LockBuffer(
|
||||
LONG lDefaultStride, // Minimum stride (with no padding).
|
||||
DWORD dwHeightInPixels, // Height of the image, in pixels.
|
||||
BYTE **ppbScanLine0, // Receives a pointer to the start of scan line 0.
|
||||
LONG *plStride // Receives the actual stride.
|
||||
)
|
||||
{
|
||||
HRESULT hr = S_OK;
|
||||
|
||||
// Use the 2-D version if available.
|
||||
if (m_p2DBuffer)
|
||||
{
|
||||
hr = m_p2DBuffer->Lock2D(ppbScanLine0, plStride);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Use non-2D version.
|
||||
BYTE *pData = NULL;
|
||||
|
||||
hr = m_pBuffer->Lock(&pData, NULL, NULL);
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
*plStride = lDefaultStride;
|
||||
if (lDefaultStride < 0)
|
||||
{
|
||||
// Bottom-up orientation. Return a pointer to the start of the
|
||||
// last row *in memory* which is the top row of the image.
|
||||
*ppbScanLine0 = pData + abs(lDefaultStride) * (dwHeightInPixels - 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Top-down orientation. Return a pointer to the start of the
|
||||
// buffer.
|
||||
*ppbScanLine0 = pData;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
m_bLocked = (SUCCEEDED(hr));
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// UnlockBuffer
|
||||
//
|
||||
// Unlocks the buffer. Called automatically by the destructor.
|
||||
//-------------------------------------------------------------------
|
||||
|
||||
void UnlockBuffer()
|
||||
{
|
||||
if (m_bLocked)
|
||||
{
|
||||
if (m_p2DBuffer)
|
||||
{
|
||||
(void)m_p2DBuffer->Unlock2D();
|
||||
}
|
||||
else
|
||||
{
|
||||
(void)m_pBuffer->Unlock();
|
||||
}
|
||||
m_bLocked = FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
IMFMediaBuffer *m_pBuffer;
|
||||
IMF2DBuffer *m_p2DBuffer;
|
||||
|
||||
BOOL m_bLocked;
|
||||
};
|
695
Windows/CaptureDevice.cpp
Normal file
695
Windows/CaptureDevice.cpp
Normal file
|
@ -0,0 +1,695 @@
|
|||
// Copyright (c) 2020- PPSSPP Project.
|
||||
|
||||
// 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, version 2.0 or later versions.
|
||||
|
||||
// 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 2.0 for more details.
|
||||
|
||||
// A copy of the GPL 2.0 should have been included with the program.
|
||||
// If not, see http://www.gnu.org/licenses/
|
||||
|
||||
// Official git repository and contact information can be found at
|
||||
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
|
||||
|
||||
#include <shlwapi.h>
|
||||
#include "thread/threadutil.h"
|
||||
#include "CaptureDevice.h"
|
||||
#include "BufferLock.h"
|
||||
#include "ext/jpge/jpge.h"
|
||||
#include "Core/HLE/sceUsbCam.h"
|
||||
#include "Core/Config.h"
|
||||
|
||||
WindowsCaptureDevice *winCamera;
|
||||
|
||||
// TODO: Add more formats, but need some tests.
|
||||
VideoFormatTransform g_VideoFormats[] =
|
||||
{
|
||||
{ MFVideoFormat_RGB32, AV_PIX_FMT_RGBA },
|
||||
{ MFVideoFormat_RGB24, AV_PIX_FMT_RGB24 },
|
||||
{ MFVideoFormat_YUY2, AV_PIX_FMT_YUYV422 },
|
||||
{ MFVideoFormat_NV12, AV_PIX_FMT_NV12 }
|
||||
};
|
||||
|
||||
const int g_cVideoFormats = 4;
|
||||
|
||||
|
||||
MediaParam defaultVideoParam = { 480, 272, 0, MFVideoFormat_RGB24 };
|
||||
MediaParam defaultAudioParam = { 44100, 2, 0, MFAudioFormat_PCM };
|
||||
|
||||
HRESULT GetDefaultStride(IMFMediaType *pType, LONG *plStride);
|
||||
|
||||
ReaderCallback::ReaderCallback(WindowsCaptureDevice *device): img_convert_ctx(nullptr){
|
||||
this->device = device;
|
||||
}
|
||||
|
||||
ReaderCallback::~ReaderCallback() {
|
||||
sws_freeContext(img_convert_ctx);
|
||||
}
|
||||
|
||||
HRESULT ReaderCallback::QueryInterface(REFIID riid, void** ppv)
|
||||
{
|
||||
static const QITAB qit[] =
|
||||
{
|
||||
QITABENT(ReaderCallback, IMFSourceReaderCallback),
|
||||
{ 0 },
|
||||
};
|
||||
return QISearch(this, qit, riid, ppv);
|
||||
}
|
||||
|
||||
HRESULT ReaderCallback::OnReadSample(
|
||||
HRESULT hrStatus,
|
||||
DWORD dwStreamIndex,
|
||||
DWORD dwStreamFlags,
|
||||
LONGLONG llTimestamp,
|
||||
IMFSample *pSample) {
|
||||
HRESULT hr = S_OK;
|
||||
IMFMediaBuffer *pBuffer = nullptr;
|
||||
LONG lStride = 0;
|
||||
std::lock_guard<std::mutex> lock(device->sdMutex);
|
||||
if (device->isShutDown())
|
||||
return hr;
|
||||
|
||||
if (FAILED(hrStatus))
|
||||
hr = hrStatus;
|
||||
|
||||
if (SUCCEEDED(hr)) {
|
||||
if (pSample) {
|
||||
hr = pSample->GetBufferByIndex(0, &pBuffer);
|
||||
}
|
||||
}
|
||||
if (SUCCEEDED(hr)) {
|
||||
switch (device->type) {
|
||||
case CAPTUREDEVIDE_TYPE::VIDEO: {
|
||||
BYTE *pbScanline0 = nullptr;
|
||||
VideoBufferLock *videoBuffer = nullptr;
|
||||
int imgJpegSize = device->imgJpegSize;
|
||||
unsigned char* invertedSrcImg = nullptr;
|
||||
LONG srcPadding = 0;
|
||||
|
||||
UINT32 srcW = device->deviceParam.width;
|
||||
UINT32 srcH = device->deviceParam.height;
|
||||
UINT32 dstW = device->targetMediaParam.width;
|
||||
UINT32 dstH = device->targetMediaParam.height;
|
||||
GUID srcMFVideoFormat = device->deviceParam.videoFormat;
|
||||
|
||||
// pSample can be null, in this case ReadSample still should be called to request next frame.
|
||||
if (pSample) {
|
||||
videoBuffer = new VideoBufferLock(pBuffer);
|
||||
hr = videoBuffer->LockBuffer(device->deviceParam.default_stride, device->deviceParam.height, &pbScanline0, &lStride);
|
||||
|
||||
if (lStride > 0)
|
||||
srcPadding = lStride - device->deviceParam.default_stride;
|
||||
else
|
||||
srcPadding = device->deviceParam.default_stride - lStride;
|
||||
|
||||
if (SUCCEEDED(hr)) {
|
||||
// Convert image to RGB24
|
||||
if (lStride > 0) {
|
||||
imgConvert(
|
||||
device->imageRGB, dstW, dstH, device->imgRGBLineSizes,
|
||||
pbScanline0, srcW, srcH, srcMFVideoFormat, srcPadding);
|
||||
}
|
||||
else {
|
||||
// If stride < 0, the pointer to the first row of source image is the last row in memory,should invert it in memory.
|
||||
invertedSrcImg = (unsigned char*)av_malloc(av_image_get_buffer_size(getAVVideoFormatbyMFVideoFormat(srcMFVideoFormat), srcW, srcH, 1));
|
||||
imgInvert(invertedSrcImg, pbScanline0, srcW, srcH, device->deviceParam.videoFormat, lStride);
|
||||
// We alloc a inverted image with no padding, set padding to zero.
|
||||
srcPadding = 0;
|
||||
imgConvert(
|
||||
device->imageRGB, dstW, dstH, device->imgRGBLineSizes,
|
||||
invertedSrcImg, srcW, srcH, srcMFVideoFormat, srcPadding);
|
||||
av_free(invertedSrcImg);
|
||||
}
|
||||
|
||||
// Compress image to jpeg from RGB24.
|
||||
jpge::compress_image_to_jpeg_file_in_memory(
|
||||
device->imageJpeg, imgJpegSize,
|
||||
dstW,
|
||||
dstH,
|
||||
3,
|
||||
device->imageRGB);
|
||||
}
|
||||
Camera::pushCameraImage(imgJpegSize, device->imageJpeg);
|
||||
}
|
||||
// Request the next frame.
|
||||
if (SUCCEEDED(hr)) {
|
||||
hr = device->m_pReader->ReadSample(
|
||||
(DWORD)MF_SOURCE_READER_FIRST_VIDEO_STREAM,
|
||||
0,
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr
|
||||
);
|
||||
}
|
||||
|
||||
delete videoBuffer;
|
||||
break;
|
||||
}
|
||||
case CAPTUREDEVIDE_TYPE::AUDIO:
|
||||
// TODO:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
SafeRelease(&pBuffer);
|
||||
return hr;
|
||||
}
|
||||
|
||||
AVPixelFormat ReaderCallback::getAVVideoFormatbyMFVideoFormat(const GUID &MFVideoFormat) {
|
||||
for (int i = 0; i < g_cVideoFormats; i++) {
|
||||
if (MFVideoFormat == g_VideoFormats[i].MFVideoFormat)
|
||||
return g_VideoFormats[i].AVVideoFormat;
|
||||
}
|
||||
return AV_PIX_FMT_RGB24;
|
||||
}
|
||||
|
||||
void ReaderCallback::imgConvert(
|
||||
unsigned char *dst, unsigned int &dstW, unsigned int &dstH, int dstLineSizes[4],
|
||||
unsigned char *src, const unsigned int &srcW, const unsigned int &srcH, const GUID &srcFormat,
|
||||
const int &srcPadding) {
|
||||
int srcLineSizes[4] = { 0, 0, 0, 0 };
|
||||
unsigned char *pSrc[4];
|
||||
unsigned char *pDst[4];
|
||||
|
||||
AVPixelFormat srcAvFormat = getAVVideoFormatbyMFVideoFormat(srcFormat);
|
||||
|
||||
av_image_fill_linesizes(srcLineSizes, srcAvFormat, srcW);
|
||||
|
||||
// Is this correct?
|
||||
if (srcPadding != 0) {
|
||||
for (int i = 0; i < 4; i++) {
|
||||
if (srcLineSizes[i] != 0)
|
||||
srcLineSizes[i] += srcPadding;
|
||||
}
|
||||
}
|
||||
|
||||
av_image_fill_pointers(pSrc, srcAvFormat, srcH, src, srcLineSizes);
|
||||
av_image_fill_pointers(pDst, AV_PIX_FMT_RGB24, dstH, dst, dstLineSizes);
|
||||
|
||||
|
||||
|
||||
if (img_convert_ctx == nullptr) {
|
||||
img_convert_ctx = sws_getContext(
|
||||
srcW,
|
||||
srcH,
|
||||
srcAvFormat,
|
||||
dstW,
|
||||
dstH,
|
||||
AV_PIX_FMT_RGB24,
|
||||
SWS_BICUBIC,
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr
|
||||
);
|
||||
}
|
||||
|
||||
if (img_convert_ctx) {
|
||||
sws_scale(img_convert_ctx,
|
||||
(const uint8_t *const *)pSrc,
|
||||
srcLineSizes,
|
||||
0,
|
||||
srcH,
|
||||
(uint8_t *const *)pDst,
|
||||
dstLineSizes
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
void ReaderCallback::imgInvert(unsigned char *dst, unsigned char *src, const int &srcW, const int &srcH, const GUID &srcFormat, const int &srcStride) {
|
||||
AVPixelFormat srcAvFormat = getAVVideoFormatbyMFVideoFormat(srcFormat);
|
||||
int dstLineSizes[4] = { 0, 0, 0, 0 };
|
||||
|
||||
av_image_fill_linesizes(dstLineSizes, srcAvFormat, srcW);
|
||||
|
||||
if(srcFormat == MFVideoFormat_RGB32)
|
||||
imgInvertRGBA(dst, dstLineSizes[0], src, srcStride, srcH);
|
||||
else if(srcFormat == MFVideoFormat_RGB24)
|
||||
imgInvertRGB(dst, dstLineSizes[0], src, srcStride, srcH);
|
||||
else if (srcFormat == MFVideoFormat_YUY2)
|
||||
imgInvertYUY2(dst, dstLineSizes[0], src, srcStride, srcH);
|
||||
else if (srcFormat == MFVideoFormat_NV12)
|
||||
imgInvertNV12(dst, dstLineSizes[0], src, srcStride, srcH);;
|
||||
}
|
||||
|
||||
void ReaderCallback::imgInvertRGBA(unsigned char *dst, int &dstStride, unsigned char *src, const int &srcStride, const int &h) {
|
||||
MFCopyImage(dst, dstStride, src, srcStride, dstStride, h);
|
||||
}
|
||||
|
||||
void ReaderCallback::imgInvertRGB(unsigned char *dst, int &dstStride, unsigned char *src, const int &srcStride, const int &h) {
|
||||
for (int y = 0; y < h; y++) {
|
||||
for (int srcx = dstStride - 1, dstx = 0; dstx < dstStride; srcx--, dstx++) {
|
||||
dst[dstx] = src[srcx];
|
||||
}
|
||||
dst += dstStride;
|
||||
src += srcStride;
|
||||
}
|
||||
}
|
||||
|
||||
void ReaderCallback::imgInvertYUY2(unsigned char *dst, int &dstStride, unsigned char *src, const int &srcStride, const int &h) {
|
||||
for (int y = 0; y < h; y++) {
|
||||
for (int srcx = dstStride - 1, dstx = 0; dstx < dstStride; srcx--, dstx++) {
|
||||
dst[dstx] = src[srcx];
|
||||
}
|
||||
dst += dstStride;
|
||||
src += srcStride;
|
||||
}
|
||||
}
|
||||
|
||||
void ReaderCallback::imgInvertNV12(unsigned char *dst, int &dstStride, unsigned char *src, const int &srcStride, const int &h) {
|
||||
unsigned char *dstY = dst;
|
||||
unsigned char *dstU = dst + dstStride * h;
|
||||
unsigned char *srcY = src;
|
||||
unsigned char *srcV = src + srcStride * h;
|
||||
|
||||
unsigned char *srcY1 = srcY;
|
||||
unsigned char *srcY2 = srcY1 + srcStride;
|
||||
unsigned char *dstY1 = dstY;
|
||||
unsigned char *dstY2 = dstY1 + dstStride;
|
||||
|
||||
bool isodd = h % 2 != 0;
|
||||
|
||||
for (int y = 0; y < (isodd ? h - 1 : h); y += 2) {
|
||||
for (int srcx = dstStride - 1, dstx = 0; dstx < dstStride; srcx--, dstx++) {
|
||||
dstY1[dstx] = srcY1[srcx];
|
||||
dstY2[dstx] = srcY2[srcx];
|
||||
dstU[dstx] = srcV[srcx];
|
||||
}
|
||||
dstY += dstStride * 2;
|
||||
srcY1 += srcStride * 2;
|
||||
srcY2 += srcStride *2;
|
||||
srcV += srcStride;
|
||||
dstU += dstStride;
|
||||
}
|
||||
}
|
||||
|
||||
WindowsCaptureDevice::WindowsCaptureDevice(CAPTUREDEVIDE_TYPE type) :
|
||||
type(type),
|
||||
m_pCallback(nullptr),
|
||||
m_pSource(nullptr),
|
||||
m_pReader(nullptr),
|
||||
error(CAPTUREDEVIDE_ERROR_NO_ERROR),
|
||||
errorMessage(""),
|
||||
state(CAPTUREDEVIDE_STATE::UNINITIALIZED) {
|
||||
|
||||
switch (type) {
|
||||
case CAPTUREDEVIDE_TYPE::VIDEO:
|
||||
targetMediaParam = defaultVideoParam;
|
||||
imageRGB = (unsigned char*)av_malloc(av_image_get_buffer_size(AV_PIX_FMT_RGB24, targetMediaParam.width, targetMediaParam.height, 1));
|
||||
av_image_fill_linesizes(imgRGBLineSizes, AV_PIX_FMT_RGB24, targetMediaParam.width);
|
||||
imgJpegSize = av_image_get_buffer_size(AV_PIX_FMT_YUVJ411P, targetMediaParam.width, targetMediaParam.height, 1);
|
||||
imageJpeg = (unsigned char*)av_malloc(imgJpegSize);
|
||||
break;
|
||||
case CAPTUREDEVIDE_TYPE::AUDIO:
|
||||
// TODO:
|
||||
targetMediaParam = defaultAudioParam;
|
||||
imageRGB = nullptr;
|
||||
imageJpeg = nullptr;
|
||||
break;
|
||||
}
|
||||
|
||||
std::thread t(&WindowsCaptureDevice::messageHandler, this);
|
||||
t.detach();
|
||||
}
|
||||
|
||||
WindowsCaptureDevice::~WindowsCaptureDevice() {
|
||||
switch (type) {
|
||||
case CAPTUREDEVIDE_TYPE::VIDEO:
|
||||
av_free(imageRGB);
|
||||
av_free(imageJpeg);
|
||||
break;
|
||||
case CAPTUREDEVIDE_TYPE::AUDIO:
|
||||
// TODO:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
bool WindowsCaptureDevice::init() {
|
||||
HRESULT hr = S_OK;
|
||||
param = { 0 };
|
||||
IMFAttributes *pAttributes = nullptr;
|
||||
|
||||
hr = MFCreateAttributes(&pAttributes, 1);
|
||||
if (SUCCEEDED(hr)) {
|
||||
switch (type) {
|
||||
case CAPTUREDEVIDE_TYPE::VIDEO:
|
||||
hr = pAttributes->SetGUID(
|
||||
MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE,
|
||||
MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_GUID
|
||||
);
|
||||
|
||||
break;
|
||||
case CAPTUREDEVIDE_TYPE::AUDIO:
|
||||
hr = pAttributes->SetGUID(
|
||||
MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE,
|
||||
MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_AUDCAP_GUID
|
||||
);
|
||||
|
||||
break;
|
||||
default:
|
||||
setError(CAPTUREDEVIDE_ERROR_UNKNOWN_TYPE, "Unknown device type");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (SUCCEEDED(hr))
|
||||
hr = MFEnumDeviceSources(pAttributes, ¶m.ppDevices, ¶m.count);
|
||||
|
||||
if (FAILED(hr)) {
|
||||
setError(CAPTUREDEVIDE_ERROR_INIT_FAILED, "Cannot enumerate devices");
|
||||
SafeRelease(&pAttributes);
|
||||
return false;
|
||||
}
|
||||
|
||||
SafeRelease(&pAttributes);
|
||||
updateState(CAPTUREDEVIDE_STATE::STOPPED);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WindowsCaptureDevice::start() {
|
||||
HRESULT hr = S_OK;
|
||||
IMFAttributes *pAttributes = nullptr;
|
||||
IMFMediaType *pType = nullptr;
|
||||
UINT32 selection = 0;
|
||||
UINT32 count = 0;
|
||||
std::vector<std::string> deviceList = getDeviceList();
|
||||
|
||||
if (deviceList.size() < 1) {
|
||||
setError(CAPTUREDEVIDE_ERROR_START_FAILED, "Has no device");
|
||||
return false;
|
||||
}
|
||||
|
||||
m_pCallback = new ReaderCallback(this);
|
||||
|
||||
switch (state) {
|
||||
case CAPTUREDEVIDE_STATE::STOPPED:
|
||||
for (auto &name : deviceList) {
|
||||
if (name == g_Config.sWinCameraDevice) {
|
||||
selection = count;
|
||||
break;
|
||||
}
|
||||
++count;
|
||||
}
|
||||
setSelction(selection);
|
||||
hr = param.ppDevices[param.selection]->ActivateObject(
|
||||
__uuidof(IMFMediaSource),
|
||||
(void**)&m_pSource);
|
||||
|
||||
if (SUCCEEDED(hr))
|
||||
hr = MFCreateAttributes(&pAttributes, 2);
|
||||
|
||||
// Use async mode
|
||||
if (SUCCEEDED(hr))
|
||||
hr = pAttributes->SetUnknown(MF_SOURCE_READER_ASYNC_CALLBACK, m_pCallback);
|
||||
|
||||
if (SUCCEEDED(hr))
|
||||
hr = pAttributes->SetUINT32(MF_READWRITE_DISABLE_CONVERTERS, TRUE);
|
||||
|
||||
if (SUCCEEDED(hr)) {
|
||||
hr = MFCreateSourceReaderFromMediaSource(
|
||||
m_pSource,
|
||||
pAttributes,
|
||||
&m_pReader
|
||||
);
|
||||
}
|
||||
|
||||
if (!m_pReader)
|
||||
hr = -1;
|
||||
|
||||
if (SUCCEEDED(hr)) {
|
||||
switch (type) {
|
||||
case CAPTUREDEVIDE_TYPE::VIDEO:
|
||||
hr = m_pReader->GetNativeMediaType(
|
||||
(DWORD)MF_SOURCE_READER_FIRST_VIDEO_STREAM,
|
||||
(DWORD)0xFFFFFFFF,//MF_SOURCE_READER_CURRENT_TYPE_INDEX
|
||||
&pType
|
||||
);
|
||||
if (SUCCEEDED(hr))
|
||||
hr = setDeviceParam(pType);
|
||||
|
||||
// Request the first frame, in asnyc mode, OnReadSample will be called when ReadSample completed.
|
||||
if (SUCCEEDED(hr)) {
|
||||
hr = m_pReader->ReadSample(
|
||||
(DWORD)MF_SOURCE_READER_FIRST_VIDEO_STREAM,
|
||||
0,
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr
|
||||
);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case CAPTUREDEVIDE_TYPE::AUDIO:
|
||||
// TODO:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (FAILED(hr)) {
|
||||
setError(CAPTUREDEVIDE_ERROR_START_FAILED, "Cannot start");
|
||||
if(m_pSource)
|
||||
m_pSource->Shutdown();
|
||||
SafeRelease(&m_pSource);
|
||||
SafeRelease(&pAttributes);
|
||||
SafeRelease(&pType);
|
||||
SafeRelease(&m_pReader);
|
||||
return false;
|
||||
}
|
||||
|
||||
SafeRelease(&pAttributes);
|
||||
SafeRelease(&pType);
|
||||
updateState(CAPTUREDEVIDE_STATE::STARTED);
|
||||
break;
|
||||
case CAPTUREDEVIDE_STATE::LOST:
|
||||
setError(CAPTUREDEVIDE_ERROR_START_FAILED, "Device has lost");
|
||||
return false;
|
||||
case CAPTUREDEVIDE_STATE::STARTED:
|
||||
setError(CAPTUREDEVIDE_ERROR_START_FAILED, "Device has started");
|
||||
return false;
|
||||
case CAPTUREDEVIDE_STATE::UNINITIALIZED:
|
||||
setError(CAPTUREDEVIDE_ERROR_START_FAILED, "Device doesn't initialize");
|
||||
return false;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WindowsCaptureDevice::stop() {
|
||||
if (state == CAPTUREDEVIDE_STATE::STOPPED)
|
||||
return true;
|
||||
if (m_pSource)
|
||||
m_pSource->Stop();
|
||||
|
||||
updateState(CAPTUREDEVIDE_STATE::STOPPED);
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
std::vector<std::string> WindowsCaptureDevice::getDeviceList(int *pActuallCount) {
|
||||
HRESULT hr = S_OK;
|
||||
UINT32 count = 0;
|
||||
LPWSTR pwstrName = nullptr;
|
||||
char *cstrName = nullptr;
|
||||
std::string strName;
|
||||
DWORD dwMinSize = 0;
|
||||
std::vector<std::string> deviceList;
|
||||
|
||||
for (; count < param.count; count++) {
|
||||
hr = param.ppDevices[count]->GetAllocatedString(
|
||||
MF_DEVSOURCE_ATTRIBUTE_FRIENDLY_NAME,
|
||||
&pwstrName,
|
||||
nullptr
|
||||
);
|
||||
|
||||
if (SUCCEEDED(hr)) {
|
||||
// Get the size needed first
|
||||
dwMinSize = WideCharToMultiByte(CP_OEMCP, NULL, pwstrName, -1, nullptr, 0, nullptr, FALSE);
|
||||
if (dwMinSize == 0)
|
||||
hr = -1;
|
||||
}
|
||||
if (SUCCEEDED(hr)) {
|
||||
cstrName = new char[dwMinSize];
|
||||
WideCharToMultiByte(CP_OEMCP, NULL, pwstrName, -1, cstrName, dwMinSize, NULL, FALSE);
|
||||
strName = cstrName;
|
||||
delete[] cstrName;
|
||||
|
||||
deviceList.push_back(strName);
|
||||
}
|
||||
|
||||
if (FAILED(hr)) {
|
||||
setError(CAPTUREDEVIDE_ERROR_GETNAMES_FAILED, "Error occurred,gotten " + std::to_string((int)count) + " device names");
|
||||
if(pActuallCount)
|
||||
*pActuallCount = count;
|
||||
return deviceList;
|
||||
}
|
||||
}
|
||||
if (pActuallCount)
|
||||
*pActuallCount = count + 1;
|
||||
return deviceList;
|
||||
}
|
||||
|
||||
HRESULT WindowsCaptureDevice::setDeviceParam(IMFMediaType *pType) {
|
||||
HRESULT hr = S_OK;
|
||||
GUID subtype = { 0 };
|
||||
bool getFormat = false;
|
||||
|
||||
switch (type) {
|
||||
case CAPTUREDEVIDE_TYPE::VIDEO:
|
||||
hr = pType->GetGUID(MF_MT_SUBTYPE, &subtype);
|
||||
if (FAILED(hr))
|
||||
break;
|
||||
|
||||
for (int i = 0; i < g_cVideoFormats; i++) {
|
||||
if (subtype == g_VideoFormats[i].MFVideoFormat) {
|
||||
deviceParam.videoFormat = subtype;
|
||||
getFormat = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!getFormat) {
|
||||
for (int i = 0; i < g_cVideoFormats; i++) {
|
||||
hr = pType->SetGUID(MF_MT_SUBTYPE, g_VideoFormats[i].MFVideoFormat);
|
||||
if (FAILED(hr))
|
||||
continue;
|
||||
|
||||
hr = m_pReader->SetCurrentMediaType(
|
||||
(DWORD)MF_SOURCE_READER_FIRST_VIDEO_STREAM,
|
||||
NULL,
|
||||
pType
|
||||
);
|
||||
|
||||
if (SUCCEEDED(hr)) {
|
||||
deviceParam.videoFormat = g_VideoFormats[i].MFVideoFormat;
|
||||
getFormat = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (SUCCEEDED(hr))
|
||||
hr = MFGetAttributeSize(pType, MF_MT_FRAME_SIZE, &deviceParam.width, &deviceParam.height);
|
||||
|
||||
if (SUCCEEDED(hr))
|
||||
hr = GetDefaultStride(pType, &deviceParam.default_stride);
|
||||
|
||||
break;
|
||||
case CAPTUREDEVIDE_TYPE::AUDIO:
|
||||
// TODO:
|
||||
break;
|
||||
}
|
||||
|
||||
return hr;
|
||||
}
|
||||
|
||||
void WindowsCaptureDevice::sendMessage(CAPTUREDEVIDE_MESSAGE message) {
|
||||
// Must be unique lock
|
||||
std::unique_lock<std::mutex> lock(mutex);
|
||||
messageQueue.push(message);
|
||||
lock.unlock();
|
||||
cond.notify_one();
|
||||
}
|
||||
|
||||
CAPTUREDEVIDE_MESSAGE WindowsCaptureDevice::getMessage() {
|
||||
// Must be unique lock
|
||||
std::unique_lock<std::mutex> lock(mutex);
|
||||
CAPTUREDEVIDE_MESSAGE message;
|
||||
cond.wait(lock, [this]() { return !messageQueue.empty(); });
|
||||
message = messageQueue.front();
|
||||
messageQueue.pop();
|
||||
lock.unlock();
|
||||
|
||||
return message;
|
||||
}
|
||||
|
||||
void WindowsCaptureDevice::messageHandler() {
|
||||
CoInitializeEx(NULL, COINIT_MULTITHREADED);
|
||||
MFStartup(MF_VERSION);
|
||||
CAPTUREDEVIDE_MESSAGE message;
|
||||
|
||||
if (type == CAPTUREDEVIDE_TYPE::VIDEO) {
|
||||
setCurrentThreadName("Camera");
|
||||
}
|
||||
|
||||
while ((message = getMessage()).command != CAPTUREDEVIDE_COMMAND::SHUTDOWN) {
|
||||
switch (message.command) {
|
||||
case CAPTUREDEVIDE_COMMAND::INITIALIZE:
|
||||
init();
|
||||
break;
|
||||
case CAPTUREDEVIDE_COMMAND::START:
|
||||
start();
|
||||
break;
|
||||
case CAPTUREDEVIDE_COMMAND::STOP:
|
||||
stop();
|
||||
break;
|
||||
case CAPTUREDEVIDE_COMMAND::UPDATE_STATE:
|
||||
updateState((*(CAPTUREDEVIDE_STATE *)message.opacity));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (state != CAPTUREDEVIDE_STATE::STOPPED)
|
||||
stop();
|
||||
|
||||
std::lock_guard<std::mutex> lock(sdMutex);
|
||||
SafeRelease(&m_pSource);
|
||||
SafeRelease(&m_pReader);
|
||||
delete m_pCallback;
|
||||
|
||||
MFShutdown();
|
||||
CoUninitialize();
|
||||
|
||||
updateState(CAPTUREDEVIDE_STATE::SHUTDOWN);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// GetDefaultStride
|
||||
//
|
||||
// Gets the default stride for a video frame, assuming no extra padding bytes.
|
||||
//
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
HRESULT GetDefaultStride(IMFMediaType *pType, LONG *plStride)
|
||||
{
|
||||
LONG lStride = 0;
|
||||
|
||||
// Try to get the default stride from the media type.
|
||||
HRESULT hr = pType->GetUINT32(MF_MT_DEFAULT_STRIDE, (UINT32*)&lStride);
|
||||
if (FAILED(hr))
|
||||
{
|
||||
// Attribute not set. Try to calculate the default stride.
|
||||
GUID subtype = GUID_NULL;
|
||||
|
||||
UINT32 width = 0;
|
||||
UINT32 height = 0;
|
||||
|
||||
// Get the subtype and the image size.
|
||||
hr = pType->GetGUID(MF_MT_SUBTYPE, &subtype);
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
hr = MFGetAttributeSize(pType, MF_MT_FRAME_SIZE, &width, &height);
|
||||
}
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
hr = MFGetStrideForBitmapInfoHeader(subtype.Data1, width, &lStride);
|
||||
}
|
||||
|
||||
// Set the attribute for later reference.
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
(void)pType->SetUINT32(MF_MT_DEFAULT_STRIDE, UINT32(lStride));
|
||||
}
|
||||
}
|
||||
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
*plStride = lStride;
|
||||
}
|
||||
return hr;
|
||||
}
|
218
Windows/CaptureDevice.h
Normal file
218
Windows/CaptureDevice.h
Normal file
|
@ -0,0 +1,218 @@
|
|||
// Copyright (c) 2020- PPSSPP Project.
|
||||
|
||||
// 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, version 2.0 or later versions.
|
||||
|
||||
// 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 2.0 for more details.
|
||||
|
||||
// A copy of the GPL 2.0 should have been included with the program.
|
||||
// If not, see http://www.gnu.org/licenses/
|
||||
|
||||
// Official git repository and contact information can be found at
|
||||
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <mfapi.h>
|
||||
#include <mfidl.h>
|
||||
#include <Mfreadwrite.h>
|
||||
#include <mutex>
|
||||
#include <condition_variable>
|
||||
#include <vector>
|
||||
#include <queue>
|
||||
#include <thread>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#include "libavformat/avformat.h"
|
||||
#include "libswscale/swscale.h"
|
||||
#include "libavutil/imgutils.h"
|
||||
}
|
||||
#endif // __cplusplus
|
||||
|
||||
struct VideoFormatTransform {
|
||||
GUID MFVideoFormat;
|
||||
AVPixelFormat AVVideoFormat;
|
||||
};
|
||||
|
||||
enum class CAPTUREDEVIDE_TYPE {
|
||||
VIDEO,
|
||||
AUDIO
|
||||
};
|
||||
|
||||
enum class CAPTUREDEVIDE_STATE {
|
||||
UNINITIALIZED,
|
||||
LOST,
|
||||
STOPPED,
|
||||
STARTED,
|
||||
SHUTDOWN
|
||||
};
|
||||
|
||||
enum class CAPTUREDEVIDE_COMMAND {
|
||||
INITIALIZE,
|
||||
START,
|
||||
STOP,
|
||||
SHUTDOWN,
|
||||
UPDATE_STATE
|
||||
};
|
||||
|
||||
enum CAPTUREDEVIDE_ERROR {
|
||||
CAPTUREDEVIDE_ERROR_NO_ERROR,
|
||||
CAPTUREDEVIDE_ERROR_UNKNOWN_TYPE = 0x80000001,
|
||||
CAPTUREDEVIDE_ERROR_INIT_FAILED,
|
||||
CAPTUREDEVIDE_ERROR_START_FAILED,
|
||||
CAPTUREDEVIDE_ERROR_STOP_FAILED,
|
||||
CAPTUREDEVIDE_ERROR_GETNAMES_FAILED
|
||||
};
|
||||
|
||||
struct CAPTUREDEVIDE_MESSAGE{
|
||||
CAPTUREDEVIDE_COMMAND command;
|
||||
void *opacity;
|
||||
};
|
||||
|
||||
struct ChooseDeviceParam {
|
||||
IMFActivate **ppDevices;
|
||||
UINT32 count;
|
||||
UINT32 selection;
|
||||
};
|
||||
|
||||
union MediaParam {
|
||||
struct {
|
||||
UINT32 width;
|
||||
UINT32 height;
|
||||
LONG default_stride;
|
||||
GUID videoFormat;
|
||||
};
|
||||
struct {
|
||||
UINT32 sampleRate;
|
||||
UINT32 channels;
|
||||
LONG padding;
|
||||
GUID audioFomat;
|
||||
};
|
||||
};
|
||||
|
||||
template <class T> void SafeRelease(T **ppT) {
|
||||
if (*ppT) {
|
||||
(*ppT)->Release();
|
||||
*ppT = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
class WindowsCaptureDevice;
|
||||
|
||||
class ReaderCallback : public IMFSourceReaderCallback {
|
||||
public:
|
||||
ReaderCallback(WindowsCaptureDevice *device);
|
||||
~ReaderCallback();
|
||||
|
||||
// IUnknown methods.
|
||||
STDMETHODIMP QueryInterface(REFIID iid, void** ppv);
|
||||
STDMETHODIMP_(ULONG) AddRef() { return 0; } // Unused, just define.
|
||||
STDMETHODIMP_(ULONG) Release() { return 0; } // Unused, just define.
|
||||
|
||||
// IMFSourceReaderCallback methods.
|
||||
STDMETHODIMP OnReadSample(
|
||||
HRESULT hrStatus,
|
||||
DWORD dwStreamIndex,
|
||||
DWORD dwStreamFlags,
|
||||
LONGLONG llTimestamp,
|
||||
IMFSample *pSample // Can be null,even if hrStatus is success.
|
||||
);
|
||||
|
||||
STDMETHODIMP OnEvent(DWORD, IMFMediaEvent *) { return S_OK; }
|
||||
STDMETHODIMP OnFlush(DWORD) { return S_OK; }
|
||||
|
||||
AVPixelFormat getAVVideoFormatbyMFVideoFormat(const GUID &MFVideoFormat);
|
||||
|
||||
/*
|
||||
* Always convet the image to RGB24
|
||||
* @param dst/src pointer to destination/source image
|
||||
* @param dstW/srcW, dstH/srcH destination/source image's width and height in pixels
|
||||
* @param dstLineSizes get the linesize of each plane by av_image_fill_linesizes()
|
||||
* @param srcFormat MF_MT_SUBTYPE attribute of source image
|
||||
* @param srcPadding should be setted to non-zero if source image has padding
|
||||
*/
|
||||
void imgConvert(
|
||||
unsigned char *dst, unsigned int &dstW, unsigned int &dstH, int dstLineSizes[4],
|
||||
unsigned char *src, const unsigned int &srcW, const unsigned int &srcH, const GUID &srcFormat,
|
||||
const int &srcPadding);
|
||||
|
||||
// Flip image start and end in memory, it is neccessary if stride of source image is a negative value
|
||||
// Might need some tests in different machine.
|
||||
void imgInvert(unsigned char *dst, unsigned char *src, const int &srcW, const int &srcH, const GUID &srcFormat, const int &srcStride);
|
||||
void imgInvertRGBA(unsigned char *dst, int &dstStride, unsigned char *src, const int &srcStride, const int &h);
|
||||
void imgInvertRGB(unsigned char *dst, int &dstStride, unsigned char *src, const int &srcStride, const int &h);
|
||||
void imgInvertYUY2(unsigned char *dst, int &dstStride, unsigned char *src, const int &srcStride, const int &h);
|
||||
void imgInvertNV12(unsigned char *dst, int &dstStride, unsigned char *src, const int &srcStride, const int &h);
|
||||
|
||||
|
||||
protected:
|
||||
WindowsCaptureDevice *device;
|
||||
SwsContext *img_convert_ctx;
|
||||
};
|
||||
|
||||
class WindowsCaptureDevice {
|
||||
public:
|
||||
WindowsCaptureDevice(CAPTUREDEVIDE_TYPE type);
|
||||
~WindowsCaptureDevice();
|
||||
|
||||
bool init();
|
||||
bool start();
|
||||
bool stop();
|
||||
|
||||
CAPTUREDEVIDE_ERROR getError() const { return error; }
|
||||
std::string getErrorMessage() const { return errorMessage; }
|
||||
int getDeviceCounts() const { return param.count; }
|
||||
// Get a list contained friendly device name.
|
||||
std::vector<std::string> getDeviceList(int *pActuallCount = nullptr);
|
||||
|
||||
void setError(const CAPTUREDEVIDE_ERROR &newError, const std::string &newErrorMessage) { error = newError; errorMessage = newErrorMessage; }
|
||||
void setSelction(const UINT32 &selection) { param.selection = selection; }
|
||||
void updateState(const CAPTUREDEVIDE_STATE &newState) { state = newState; }
|
||||
HRESULT setDeviceParam(IMFMediaType *pType);
|
||||
|
||||
bool isShutDown() const { return state == CAPTUREDEVIDE_STATE::SHUTDOWN; }
|
||||
|
||||
void sendMessage(CAPTUREDEVIDE_MESSAGE message);
|
||||
CAPTUREDEVIDE_MESSAGE getMessage();
|
||||
|
||||
friend class ReaderCallback;
|
||||
|
||||
protected:
|
||||
// Handle message here.
|
||||
void messageHandler();
|
||||
|
||||
CAPTUREDEVIDE_TYPE type;
|
||||
MediaParam deviceParam;
|
||||
MediaParam targetMediaParam;
|
||||
CAPTUREDEVIDE_STATE state;
|
||||
ChooseDeviceParam param;
|
||||
|
||||
CAPTUREDEVIDE_ERROR error;
|
||||
std::string errorMessage;
|
||||
|
||||
// MF interface.
|
||||
ReaderCallback *m_pCallback;
|
||||
IMFSourceReader *m_pReader;
|
||||
IMFMediaSource *m_pSource;
|
||||
|
||||
// Message loop.
|
||||
std::mutex mutex;
|
||||
std::condition_variable cond;
|
||||
std::queue<CAPTUREDEVIDE_MESSAGE> messageQueue;
|
||||
|
||||
// For the shutdown event safety.
|
||||
std::mutex sdMutex;
|
||||
|
||||
// Camera only
|
||||
unsigned char *imageRGB;
|
||||
int imgRGBLineSizes[4];
|
||||
unsigned char *imageJpeg;
|
||||
int imgJpegSize;
|
||||
};
|
||||
|
||||
extern WindowsCaptureDevice *winCamera;
|
|
@ -238,7 +238,7 @@
|
|||
<PrecompiledHeader>Use</PrecompiledHeader>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
|
||||
<AdditionalIncludeDirectories>../dx9sdk/Include/DX11;../ext;../common;..;../ext/native;../ext/glew;../ext/zlib</AdditionalIncludeDirectories>
|
||||
<AdditionalIncludeDirectories>..\ffmpeg\WindowsInclude;..\ffmpeg\Windows\x86_64\include;../dx9sdk/Include/DX11;../ext;../common;..;../ext/native;../ext/glew;../ext/zlib</AdditionalIncludeDirectories>
|
||||
<ForcedIncludeFiles>stdafx.h;Common/DbgNew.h</ForcedIncludeFiles>
|
||||
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
|
||||
<EnableEnhancedInstructionSet>StreamingSIMDExtensions2</EnableEnhancedInstructionSet>
|
||||
|
@ -249,7 +249,7 @@
|
|||
<AdditionalOptions>$(EXTERNAL_COMPILE_OPTIONS)</AdditionalOptions>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<AdditionalDependencies>Winmm.lib;Ws2_32.lib;opengl32.lib;dsound.lib;glu32.lib;comctl32.lib;d3d9.lib;dxguid.lib;..\ffmpeg\Windows\x86\lib\avcodec.lib;..\ffmpeg\Windows\x86\lib\avformat.lib;..\ffmpeg\Windows\x86\lib\avutil.lib;..\ffmpeg\Windows\x86\lib\swresample.lib;..\ffmpeg\Windows\x86\lib\swscale.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalDependencies>mf.lib;mfplat.lib;mfreadwrite.lib;mfuuid.lib;shlwapi.lib;Winmm.lib;Ws2_32.lib;opengl32.lib;dsound.lib;glu32.lib;comctl32.lib;d3d9.lib;dxguid.lib;..\ffmpeg\Windows\x86\lib\avcodec.lib;..\ffmpeg\Windows\x86\lib\avformat.lib;..\ffmpeg\Windows\x86\lib\avutil.lib;..\ffmpeg\Windows\x86\lib\swresample.lib;..\ffmpeg\Windows\x86\lib\swscale.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<TargetMachine>MachineX86</TargetMachine>
|
||||
|
@ -275,7 +275,7 @@
|
|||
<PrecompiledHeader>Use</PrecompiledHeader>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
|
||||
<AdditionalIncludeDirectories>../dx9sdk/Include/DX11;../ext;../common;..;../ext/native;../ext/glew;../ext/zlib</AdditionalIncludeDirectories>
|
||||
<AdditionalIncludeDirectories>..\ffmpeg\WindowsInclude;..\ffmpeg\Windows\x86_64\include;../dx9sdk/Include/DX11;../ext;../common;..;../ext/native;../ext/glew;../ext/zlib</AdditionalIncludeDirectories>
|
||||
<ForcedIncludeFiles>stdafx.h;Common/DbgNew.h</ForcedIncludeFiles>
|
||||
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
|
||||
<OmitFramePointers>false</OmitFramePointers>
|
||||
|
@ -287,7 +287,7 @@
|
|||
<AdditionalOptions>$(EXTERNAL_COMPILE_OPTIONS)</AdditionalOptions>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<AdditionalDependencies>Winmm.lib;Ws2_32.lib;opengl32.lib;dsound.lib;glu32.lib;comctl32.lib;d3d9.lib;dxguid.lib;..\ffmpeg\Windows\x86_64\lib\avcodec.lib;..\ffmpeg\Windows\x86_64\lib\avformat.lib;..\ffmpeg\Windows\x86_64\lib\avutil.lib;..\ffmpeg\Windows\x86_64\lib\swresample.lib;..\ffmpeg\Windows\x86_64\lib\swscale.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalDependencies>mf.lib;mfplat.lib;mfreadwrite.lib;mfuuid.lib;shlwapi.lib;Winmm.lib;Ws2_32.lib;opengl32.lib;dsound.lib;glu32.lib;comctl32.lib;d3d9.lib;dxguid.lib;..\ffmpeg\Windows\x86_64\lib\avcodec.lib;..\ffmpeg\Windows\x86_64\lib\avformat.lib;..\ffmpeg\Windows\x86_64\lib\avutil.lib;..\ffmpeg\Windows\x86_64\lib\swresample.lib;..\ffmpeg\Windows\x86_64\lib\swscale.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<ProgramDatabaseFile>$(OutDir)$(ProjectName).pdb</ProgramDatabaseFile>
|
||||
<LargeAddressAware>true</LargeAddressAware>
|
||||
|
@ -342,7 +342,7 @@
|
|||
<PrecompiledHeader>Use</PrecompiledHeader>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
|
||||
<AdditionalIncludeDirectories>../dx9sdk/Include/DX11;../ext;../common;..;../ext/native;../ext/glew;../ext/zlib</AdditionalIncludeDirectories>
|
||||
<AdditionalIncludeDirectories>..\ffmpeg\WindowsInclude;..\ffmpeg\Windows\x86_64\include;../dx9sdk/Include/DX11;../ext;../common;..;../ext/native;../ext/glew;../ext/zlib</AdditionalIncludeDirectories>
|
||||
<ForcedIncludeFiles>stdafx.h</ForcedIncludeFiles>
|
||||
<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
|
||||
<OmitFramePointers>false</OmitFramePointers>
|
||||
|
@ -354,7 +354,7 @@
|
|||
<AdditionalOptions>$(EXTERNAL_COMPILE_OPTIONS)</AdditionalOptions>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<AdditionalDependencies>oleaut32.lib;comdlg32.lib;shell32.lib;user32.lib;gdi32.lib;advapi32.lib;ole32.lib;Winmm.lib;Ws2_32.lib;dsound.lib;comctl32.lib;d3d9.lib;dxguid.lib;..\ffmpeg\Windows\arm\lib\avcodec.lib;..\ffmpeg\Windows\arm\lib\avformat.lib;..\ffmpeg\Windows\arm\lib\avutil.lib;..\ffmpeg\Windows\arm\lib\swresample.lib;..\ffmpeg\Windows\arm\lib\swscale.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalDependencies>mf.lib;mfplat.lib;mfreadwrite.lib;mfuuid.lib;shlwapi.lib;oleaut32.lib;comdlg32.lib;shell32.lib;user32.lib;gdi32.lib;advapi32.lib;ole32.lib;Winmm.lib;Ws2_32.lib;dsound.lib;comctl32.lib;d3d9.lib;dxguid.lib;..\ffmpeg\Windows\arm\lib\avcodec.lib;..\ffmpeg\Windows\arm\lib\avformat.lib;..\ffmpeg\Windows\arm\lib\avutil.lib;..\ffmpeg\Windows\arm\lib\swresample.lib;..\ffmpeg\Windows\arm\lib\swscale.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<ProgramDatabaseFile>$(OutDir)$(ProjectName).pdb</ProgramDatabaseFile>
|
||||
<LargeAddressAware>true</LargeAddressAware>
|
||||
|
@ -382,7 +382,7 @@
|
|||
<PrecompiledHeader>Use</PrecompiledHeader>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
|
||||
<AdditionalIncludeDirectories>../dx9sdk/Include/DX11;../ext;../common;..;../ext/native;../ext/glew;../ext/zlib</AdditionalIncludeDirectories>
|
||||
<AdditionalIncludeDirectories>..\ffmpeg\WindowsInclude;..\ffmpeg\Windows\x86_64\include;../dx9sdk/Include/DX11;../ext;../common;..;../ext/native;../ext/glew;../ext/zlib</AdditionalIncludeDirectories>
|
||||
<PrecompiledHeaderFile>stdafx.h</PrecompiledHeaderFile>
|
||||
<ForcedIncludeFiles>stdafx.h</ForcedIncludeFiles>
|
||||
<MultiProcessorCompilation>true</MultiProcessorCompilation>
|
||||
|
@ -390,7 +390,7 @@
|
|||
<AdditionalOptions>$(EXTERNAL_COMPILE_OPTIONS)</AdditionalOptions>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<AdditionalDependencies>Winmm.lib;Ws2_32.lib;opengl32.lib;dsound.lib;glu32.lib;comctl32.lib;d3d9.lib;dxguid.lib;..\ffmpeg\Windows\x86\lib\avcodec.lib;..\ffmpeg\Windows\x86\lib\avformat.lib;..\ffmpeg\Windows\x86\lib\avutil.lib;..\ffmpeg\Windows\x86\lib\swresample.lib;..\ffmpeg\Windows\x86\lib\swscale.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalDependencies>mf.lib;mfplat.lib;mfreadwrite.lib;mfuuid.lib;shlwapi.lib;Winmm.lib;Ws2_32.lib;opengl32.lib;dsound.lib;glu32.lib;comctl32.lib;d3d9.lib;dxguid.lib;..\ffmpeg\Windows\x86\lib\avcodec.lib;..\ffmpeg\Windows\x86\lib\avformat.lib;..\ffmpeg\Windows\x86\lib\avutil.lib;..\ffmpeg\Windows\x86\lib\swresample.lib;..\ffmpeg\Windows\x86\lib\swscale.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<OutputFile>$(OutDir)$(TargetName)$(TargetExt)</OutputFile>
|
||||
<AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
|
@ -431,14 +431,14 @@
|
|||
<PrecompiledHeader>Use</PrecompiledHeader>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
|
||||
<AdditionalIncludeDirectories>../dx9sdk/Include/DX11;../ext;../common;..;../ext/native;../ext/glew;../ext/zlib</AdditionalIncludeDirectories>
|
||||
<AdditionalIncludeDirectories>..\ffmpeg\WindowsInclude;..\ffmpeg\Windows\x86_64\include;../dx9sdk/Include/DX11;../ext;../common;..;../ext/native;../ext/glew;../ext/zlib</AdditionalIncludeDirectories>
|
||||
<ForcedIncludeFiles>stdafx.h</ForcedIncludeFiles>
|
||||
<MultiProcessorCompilation>true</MultiProcessorCompilation>
|
||||
<RuntimeTypeInfo>false</RuntimeTypeInfo>
|
||||
<AdditionalOptions>$(EXTERNAL_COMPILE_OPTIONS)</AdditionalOptions>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<AdditionalDependencies>Winmm.lib;Ws2_32.lib;opengl32.lib;dsound.lib;glu32.lib;comctl32.lib;d3d9.lib;dxguid.lib;..\ffmpeg\Windows\x86_64\lib\avcodec.lib;..\ffmpeg\Windows\x86_64\lib\avformat.lib;..\ffmpeg\Windows\x86_64\lib\avutil.lib;..\ffmpeg\Windows\x86_64\lib\swresample.lib;..\ffmpeg\Windows\x86_64\lib\swscale.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalDependencies>mf.lib;mfplat.lib;mfreadwrite.lib;mfuuid.lib;shlwapi.lib;Winmm.lib;Ws2_32.lib;opengl32.lib;dsound.lib;glu32.lib;comctl32.lib;d3d9.lib;dxguid.lib;..\ffmpeg\Windows\x86_64\lib\avcodec.lib;..\ffmpeg\Windows\x86_64\lib\avformat.lib;..\ffmpeg\Windows\x86_64\lib\avutil.lib;..\ffmpeg\Windows\x86_64\lib\swresample.lib;..\ffmpeg\Windows\x86_64\lib\swscale.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
|
@ -514,14 +514,14 @@
|
|||
<PrecompiledHeader>Use</PrecompiledHeader>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
|
||||
<AdditionalIncludeDirectories>../dx9sdk/Include/DX11;../ext;../common;..;../ext/native;../ext/glew;../ext/zlib</AdditionalIncludeDirectories>
|
||||
<AdditionalIncludeDirectories>..\ffmpeg\WindowsInclude;..\ffmpeg\Windows\x86_64\include;../dx9sdk/Include/DX11;../ext;../common;..;../ext/native;../ext/glew;../ext/zlib</AdditionalIncludeDirectories>
|
||||
<ForcedIncludeFiles>stdafx.h</ForcedIncludeFiles>
|
||||
<MultiProcessorCompilation>true</MultiProcessorCompilation>
|
||||
<RuntimeTypeInfo>false</RuntimeTypeInfo>
|
||||
<AdditionalOptions>$(EXTERNAL_COMPILE_OPTIONS)</AdditionalOptions>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<AdditionalDependencies>oleaut32.lib;comdlg32.lib;shell32.lib;user32.lib;gdi32.lib;advapi32.lib;ole32.lib;Winmm.lib;Ws2_32.lib;dsound.lib;comctl32.lib;d3d9.lib;dxguid.lib;..\ffmpeg\Windows\arm\lib\avcodec.lib;..\ffmpeg\Windows\arm\lib\avformat.lib;..\ffmpeg\Windows\arm\lib\avutil.lib;..\ffmpeg\Windows\arm\lib\swresample.lib;..\ffmpeg\Windows\arm\lib\swscale.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalDependencies>mf.lib;mfplat.lib;mfreadwrite.lib;mfuuid.lib;shlwapi.lib;oleaut32.lib;comdlg32.lib;shell32.lib;user32.lib;gdi32.lib;advapi32.lib;ole32.lib;Winmm.lib;Ws2_32.lib;dsound.lib;comctl32.lib;d3d9.lib;dxguid.lib;..\ffmpeg\Windows\arm\lib\avcodec.lib;..\ffmpeg\Windows\arm\lib\avformat.lib;..\ffmpeg\Windows\arm\lib\avutil.lib;..\ffmpeg\Windows\arm\lib\swresample.lib;..\ffmpeg\Windows\arm\lib\swscale.lib;%(AdditionalDependencies)</AdditionalDependencies>
|
||||
<AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
|
@ -680,6 +680,7 @@
|
|||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|ARM'">true</ExcludedFromBuild>
|
||||
</ClCompile>
|
||||
<ClCompile Include="CaptureDevice.cpp" />
|
||||
<ClCompile Include="GPU\D3D11Context.cpp" />
|
||||
<ClCompile Include="GPU\D3D9Context.cpp" />
|
||||
<ClCompile Include="Debugger\BreakpointWindow.cpp" />
|
||||
|
@ -871,6 +872,8 @@
|
|||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'">true</ExcludedFromBuild>
|
||||
<ExcludedFromBuild Condition="'$(Configuration)|$(Platform)'=='Release|ARM'">true</ExcludedFromBuild>
|
||||
</ClInclude>
|
||||
<ClInclude Include="BufferLock.h" />
|
||||
<ClInclude Include="CaptureDevice.h" />
|
||||
<ClInclude Include="GPU\D3D11Context.h" />
|
||||
<ClInclude Include="GPU\D3D9Context.h" />
|
||||
<ClInclude Include="Debugger\BreakpointWindow.h" />
|
||||
|
|
|
@ -191,6 +191,9 @@
|
|||
<ClCompile Include="WASAPIStream.cpp">
|
||||
<Filter>Windows\System</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="CaptureDevice.cpp">
|
||||
<Filter>Windows\Input</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="Debugger\CtrlDisAsmView.h">
|
||||
|
@ -354,6 +357,12 @@
|
|||
<Filter>Windows\System</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\ppsspp_config.h" />
|
||||
<ClInclude Include="CaptureDevice.h">
|
||||
<Filter>Windows\Input</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="BufferLock.h">
|
||||
<Filter>Windows\Input</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="icon1.ico">
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue