Add camera support for windows.

This commit is contained in:
shenweip 2020-01-13 15:06:02 +08:00
parent 6d8ddb7a71
commit 034a257baf
12 changed files with 1134 additions and 20 deletions

View file

@ -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()

View file

@ -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),

View file

@ -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

View file

@ -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;

View file

@ -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()));

View file

@ -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();

View file

@ -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
View 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
View 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, &param.ppDevices, &param.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
View 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;

View file

@ -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" />

View file

@ -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">