添加屏幕捕获功能

master
DESKTOP-4RNDQIC\29019 2021-10-04 22:45:36 +08:00
parent d3353c796e
commit 6798243ceb
28 changed files with 8250 additions and 44 deletions

4
.gitignore vendored
View File

@ -31,3 +31,7 @@ client/qt_gl_/yuvgl/yuvgl.pro.user.3ffb486
client/qt_gl_/yuvgl/yuvgl.pro.user.4.10-pre1 client/qt_gl_/yuvgl/yuvgl.pro.user.4.10-pre1
client/qt_gl_/yuvgl/yuvgl.pro.user.bccf4b5 client/qt_gl_/yuvgl/yuvgl.pro.user.bccf4b5
client/qt_gl_/yuvgl/yuvgl.pro.user.ed68183.4.8-pre1 client/qt_gl_/yuvgl/yuvgl.pro.user.ed68183.4.8-pre1
client/qt_gl_/yuvgl/debug/
client/qt_gl_/build-yuvgl-Desktop_Qt_5_14_0_MSVC2017_64bit-Debug/
client/qt_gl_/build-yuvgl-Desktop_Qt_5_14_0_MSVC2017_32bit-Debug/
client/qt_gl_/build-yuvgl-Desktop_Qt_5_14_0_MinGW_64_bit-Debug/

View File

@ -0,0 +1,4 @@
[requires]
ffmpeg/4.2.1
[imports]
.,* -> ./third/msvc32 @ folder=True, ignore_case=True, excludes=*.html *.jpeg

View File

@ -0,0 +1,66 @@
#include <Unknwn.h>
#include <strmif.h>
#pragma comment(lib, "strmiids.lib")
#ifndef __qedit_h__
#define __qedit_h__
///////////////////////////////////////////////////////////////////////////////////
#pragma once
///////////////////////////////////////////////////////////////////////////////////
struct __declspec(uuid("0579154a-2b53-4994-b0d0-e773148eff85"))
ISampleGrabberCB : IUnknown
{
//
// Raw methods provided by interface
//
virtual HRESULT __stdcall SampleCB(
double SampleTime,
struct IMediaSample * pSample) = 0;
virtual HRESULT __stdcall BufferCB(
double SampleTime,
unsigned char * pBuffer,
long BufferLen) = 0;
};
struct __declspec(uuid("6b652fff-11fe-4fce-92ad-0266b5d7c78f"))
ISampleGrabber : IUnknown
{
//
// Raw methods provided by interface
//
virtual HRESULT __stdcall SetOneShot(
long OneShot) = 0;
virtual HRESULT __stdcall SetMediaType(
struct _AMMediaType * pType) = 0;
virtual HRESULT __stdcall GetConnectedMediaType(
struct _AMMediaType * pType) = 0;
virtual HRESULT __stdcall SetBufferSamples(
long BufferThem) = 0;
virtual HRESULT __stdcall GetCurrentBuffer(
/*[in,out]*/ long * pBufferSize,
/*[out]*/ long * pBuffer) = 0;
virtual HRESULT __stdcall GetCurrentSample(
/*[out,retval]*/ struct IMediaSample * * ppSample) = 0;
virtual HRESULT __stdcall SetCallback(
struct ISampleGrabberCB * pCallback,
long WhichMethodToCallback) = 0;
};
static const IID IID_ISampleGrabber = { 0x6B652FFF, 0x11FE, 0x4fce,{ 0x92, 0xAD, 0x02, 0x66, 0xB5, 0xD7, 0xC7, 0x8F } };
static const IID IID_ISampleGrabberCB = { 0x0579154A, 0x2B53, 0x4994,{ 0xB0, 0xD0, 0xE7, 0x73, 0x14, 0x8E, 0xFF, 0x85 } };
static const CLSID CLSID_SampleGrabber = { 0xC1F400A0, 0x3F08, 0x11d3,{ 0x9F, 0x0B, 0x00, 0x60, 0x08, 0x03, 0x9E, 0x37 } };
static const CLSID CLSID_NullRenderer = { 0xC1F400A4, 0x3F08, 0x11d3,{ 0x9F, 0x0B, 0x00, 0x60, 0x08, 0x03, 0x9E, 0x37 } };
#endif

File diff suppressed because it is too large Load Diff

View File

@ -66,6 +66,7 @@ extern void RTMP_TLS_Init();
extern TLS_CTX RTMP_TLS_ctx; extern TLS_CTX RTMP_TLS_ctx;
#include <zlib.h> #include <zlib.h>
#include "strncasecmp.h"
#endif /* CRYPTO */ #endif /* CRYPTO */

View File

@ -29,6 +29,7 @@
#include "rtmp_sys.h" #include "rtmp_sys.h"
#include "log.h" #include "log.h"
#include "strncasecmp.h"
int RTMP_ParseURL(const char *url, int *protocol, AVal *host, unsigned int *port, int RTMP_ParseURL(const char *url, int *protocol, AVal *host, unsigned int *port,
AVal *playpath, AVal *app) AVal *playpath, AVal *app)

View File

@ -31,6 +31,7 @@
#include "rtmp_sys.h" #include "rtmp_sys.h"
#include "log.h" #include "log.h"
#include "strncasecmp.h"
#ifdef CRYPTO #ifdef CRYPTO
#ifdef USE_POLARSSL #ifdef USE_POLARSSL
@ -1165,7 +1166,7 @@ RTMP_ToggleStream(RTMP *r)
return res; return res;
r->m_pausing = 1; r->m_pausing = 1;
sleep(1); msleep(1000);
} }
res = RTMP_SendPause(r, FALSE, r->m_pauseStamp); res = RTMP_SendPause(r, FALSE, r->m_pauseStamp);
r->m_pausing = 3; r->m_pausing = 3;
@ -1524,10 +1525,10 @@ RTMP_ClientPacket(RTMP *r, RTMPPacket *packet)
return bHasMediaPacket; return bHasMediaPacket;
} }
#ifdef _DEBUG //#ifdef _DEBUG
extern FILE *netstackdump; //extern FILE *netstackdump;
extern FILE *netstackdump_read; //extern FILE *netstackdump_read;
#endif //#endif
// @remark debug info by http://github.com/ossrs/srs // @remark debug info by http://github.com/ossrs/srs
unsigned long _srs_rbytes = 0; unsigned long _srs_rbytes = 0;
@ -1620,7 +1621,7 @@ ReadN(RTMP *r, char *buffer, int n)
} }
/*RTMP_Log(RTMP_LOGDEBUG, "%s: %d bytes\n", __FUNCTION__, nBytes); */ /*RTMP_Log(RTMP_LOGDEBUG, "%s: %d bytes\n", __FUNCTION__, nBytes); */
#ifdef _DEBUG #ifdef _DEBUG
fwrite(ptr, 1, nBytes, netstackdump_read); // fwrite(ptr, 1, nBytes, netstackdump_read);
#endif #endif
if (nBytes == 0) if (nBytes == 0)
@ -4469,7 +4470,7 @@ RTMPSockBuf_Send(RTMPSockBuf *sb, const char *buf, int len)
int rc; int rc;
#ifdef _DEBUG #ifdef _DEBUG
fwrite(buf, 1, len, netstackdump); // fwrite(buf, 1, len, netstackdump);
#endif #endif
#if defined(CRYPTO) && !defined(NO_SSL) #if defined(CRYPTO) && !defined(NO_SSL)

View File

@ -0,0 +1,17 @@
#ifndef STRNCASECMP_H
#define STRNCASECMP_H
#ifndef WINSHIT_INCLUDED
#define WINSHIT_INCLUDED
#if defined(WIN32) || defined(WIN64)
#define strcasecmp _stricmp
#define strncasecmp(x,y,z) _strnicmp(x,y,z)
#endif /* Def WIN32 or Def WIN64 */
#endif /* Ndef WINSHIT_INCLUDED */
#endif // STRNCASECMP_H

File diff suppressed because it is too large Load Diff

View File

@ -7,25 +7,27 @@
#include <qlibrary.h> #include <qlibrary.h>
#include <qsysinfo.h> #include <qsysinfo.h>
#include <qt_windows.h> #include <qt_windows.h>
#include "media/screen_capture.h"
#ifdef __MINGW32__ #ifdef __MINGW32__
#include <Tlhelp32.h> #include <Tlhelp32.h>
#include "winuser.h" #include "winuser.h"
#endif #endif
int RegiesterOwnType(){ int RegiesterOwnType(){
return 0; return 0;
} }
int main(int argc, char *argv[]) int main(int argc, char *argv[])
{ {
ScreenCapture g;
g.EnumScreen();
QssEventFilter filter; QssEventFilter filter;
QApplication app(argc, argv); QApplication app(argc, argv);
MainWindow main; MainWindow main;
main.setWindowTitle("视频采集rtmp推流工具"); main.setWindowTitle("직첵竟꿎桿묏야");
main.setFixedSize(1920,1080); main.setFixedSize(1920,1080);
main.show(); main.show();
return app.exec(); return app.exec();

View File

@ -70,7 +70,7 @@
</size> </size>
</property> </property>
<property name="text"> <property name="text">
<string>打开摄像头</string> <string>???????</string>
</property> </property>
</widget> </widget>
</item> </item>
@ -99,7 +99,7 @@
</size> </size>
</property> </property>
<property name="text"> <property name="text">
<string>打开麦克风</string> <string>??????</string>
</property> </property>
</widget> </widget>
</item> </item>
@ -116,7 +116,7 @@
<item> <item>
<widget class="QLabel" name="label"> <widget class="QLabel" name="label">
<property name="text"> <property name="text">
<string>rtmp推流地址</string> <string>rtmp???????</string>
</property> </property>
</widget> </widget>
</item> </item>
@ -142,7 +142,7 @@
</size> </size>
</property> </property>
<property name="text"> <property name="text">
<string>推流</string> <string>????</string>
</property> </property>
</widget> </widget>
</item> </item>

View File

@ -15,7 +15,7 @@ void AACAudioCoder::OnAudioData(const void *frameaddress, uint32_t framelen)
AACAudioCoder::AACAudioCoder(unsigned int smprate, unsigned int channel) { AACAudioCoder::AACAudioCoder(unsigned int smprate, unsigned int channel) {
AVCodecID codec_id = AV_CODEC_ID_AAC; AVCodecID codec_id = AV_CODEC_ID_AAC;
pCodec = avcodec_find_encoder_by_name("libfdk_aac"); pCodec = (AVCodec *)avcodec_find_encoder_by_name("libfdk_aac");
if (!pCodec) { if (!pCodec) {
printf("Codec not found\n"); printf("Codec not found\n");
this->mStatus = FAIL; this->mStatus = FAIL;

View File

@ -0,0 +1,683 @@
/*****************************************************************************
* DXGICapture.cpp
*
* Copyright (C) 2020 Gokhan Erdogdu <gokhan_erdogdu - at - yahoo - dot - com>
*
* DXGICapture is free software; you can redistribute it and/or modify it under
* the terms of the GNU Lesser General Public License as published by the Free
* Software Foundation; either version 2.1 of the License, or (at your option)
* any later version.
*
* DXGICapture 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 Lesser General Public License for more
* details.
*
******************************************************************************/
#include "DXGICapture.h"
#include "DXGICaptureHelper.h"
#include <chrono>
#pragma comment(lib, "D3D11.lib")
#pragma comment(lib, "d2d1.lib")
#pragma comment(lib, "windowscodecs.lib")
#pragma comment(lib, "shcore.lib") // SetProcessDpiAwareness
// Driver types supported
const D3D_DRIVER_TYPE g_DriverTypes[] =
{
D3D_DRIVER_TYPE_HARDWARE,
D3D_DRIVER_TYPE_WARP,
D3D_DRIVER_TYPE_REFERENCE,
};
const UINT g_NumDriverTypes = ARRAYSIZE(g_DriverTypes);
// Feature levels supported
const D3D_FEATURE_LEVEL g_FeatureLevels[] =
{
D3D_FEATURE_LEVEL_11_0,
D3D_FEATURE_LEVEL_10_1,
D3D_FEATURE_LEVEL_10_0,
D3D_FEATURE_LEVEL_9_1
};
const UINT g_NumFeatureLevels = ARRAYSIZE(g_FeatureLevels);
#define AUTOLOCK() ATL::CComCritSecLock<ATL::CComAutoCriticalSection> auto_lock((ATL::CComAutoCriticalSection&)(m_csLock))
//
// class CDXGICapture
//
CDXGICapture::CDXGICapture()
: m_csLock()
, m_bInitialized(FALSE)
, m_lD3DFeatureLevel(D3D_FEATURE_LEVEL_INVALID)
{
RtlZeroMemory(&m_rendererInfo, sizeof(m_rendererInfo));
RtlZeroMemory(&m_mouseInfo, sizeof(m_mouseInfo));
RtlZeroMemory(&m_tempMouseBuffer, sizeof(m_tempMouseBuffer));
RtlZeroMemory(&m_desktopOutputDesc, sizeof(m_desktopOutputDesc));
}
CDXGICapture::~CDXGICapture()
{
this->Terminate();
}
HRESULT CDXGICapture::loadMonitorInfos(ID3D11Device *pDevice)
{
CHECK_POINTER(pDevice);
HRESULT hr = S_OK;
CComPtr<ID3D11Device> ipDevice(pDevice);
// Get DXGI device
CComPtr<IDXGIDevice> ipDxgiDevice;
hr = ipDevice->QueryInterface(IID_PPV_ARGS(&ipDxgiDevice));
if (FAILED(hr)) {
return hr;
}
// Get DXGI adapter
CComPtr<IDXGIAdapter> ipDxgiAdapter;
hr = ipDxgiDevice->GetParent(IID_PPV_ARGS(&ipDxgiAdapter));
if (FAILED(hr)) {
return hr;
}
ipDxgiDevice = nullptr;
CComPtr<IDXGIOutput> ipDxgiOutput;
for (UINT i = 0; SUCCEEDED(hr); ++i)
{
ipDxgiOutput = nullptr;
hr = ipDxgiAdapter->EnumOutputs(i, &ipDxgiOutput);
if ((nullptr != ipDxgiOutput) && (hr != DXGI_ERROR_NOT_FOUND))
{
DXGI_OUTPUT_DESC DesktopDesc;
hr = ipDxgiOutput->GetDesc(&DesktopDesc);
if (FAILED(hr)) {
continue;
}
tagDublicatorMonitorInfo *pInfo;
pInfo = new (std::nothrow) tagDublicatorMonitorInfo;
if (nullptr == pInfo) {
return E_OUTOFMEMORY;
}
hr = DXGICaptureHelper::ConvertDxgiOutputToMonitorInfo(&DesktopDesc, i, pInfo);
if (FAILED(hr)) {
delete pInfo;
continue;
}
m_monitorInfos.push_back(pInfo);
}
}
ipDxgiOutput = nullptr;
ipDxgiAdapter = nullptr;
return S_OK;
}
void CDXGICapture::freeMonitorInfos()
{
size_t nCount = m_monitorInfos.size();
if (nCount == 0) {
return;
}
DublicatorMonitorInfoVec::iterator it = m_monitorInfos.begin();
DublicatorMonitorInfoVec::iterator end = m_monitorInfos.end();
for (size_t i = 0; (i < nCount) && (it != end); i++, it++) {
tagDublicatorMonitorInfo *pInfo = *it;
if (nullptr != pInfo) {
delete pInfo;
}
}
m_monitorInfos.clear();
}
HRESULT CDXGICapture::createDeviceResource(
const tagScreenCaptureFilterConfig *pConfig,
const tagDublicatorMonitorInfo *pSelectedMonitorInfo
)
{
HRESULT hr = S_OK;
CComPtr<IDXGIOutputDuplication> ipDxgiOutputDuplication;
CComPtr<ID3D11Texture2D> ipCopyTexture2D;
CComPtr<ID2D1Device> ipD2D1Device;
CComPtr<ID2D1DeviceContext> ipD2D1DeviceContext;
CComPtr<ID2D1Factory> ipD2D1Factory;
CComPtr<IWICImagingFactory> ipWICImageFactory;
CComPtr<IWICBitmap> ipWICOutputBitmap;
CComPtr<ID2D1RenderTarget> ipD2D1RenderTarget;
DXGI_OUTPUT_DESC dgixOutputDesc;
tagRendererInfo rendererInfo;
RtlZeroMemory(&dgixOutputDesc, sizeof(dgixOutputDesc));
RtlZeroMemory(&rendererInfo, sizeof(rendererInfo));
// copy configuration to renderer info
rendererInfo.MonitorIdx = pConfig->MonitorIdx;
rendererInfo.ShowCursor = pConfig->ShowCursor;
rendererInfo.RotationMode = pConfig->RotationMode;
rendererInfo.SizeMode = pConfig->SizeMode;
rendererInfo.OutputSize = pConfig->OutputSize;
// default
rendererInfo.ScaleX = 1.0f;
rendererInfo.ScaleY = 1.0f;
do
{
// Get DXGI factory
CComPtr<IDXGIDevice> ipDxgiDevice;
hr = m_ipD3D11Device->QueryInterface(IID_PPV_ARGS(&ipDxgiDevice));
CHECK_HR_BREAK(hr);
CComPtr<IDXGIAdapter> ipDxgiAdapter;
hr = ipDxgiDevice->GetParent(IID_PPV_ARGS(&ipDxgiAdapter));
CHECK_HR_BREAK(hr);
// Get output
CComPtr<IDXGIOutput> ipDxgiOutput;
hr = ipDxgiAdapter->EnumOutputs(rendererInfo.MonitorIdx, &ipDxgiOutput);
CHECK_HR_BREAK(hr);
// Get output description
hr = ipDxgiOutput->GetDesc(&dgixOutputDesc);
CHECK_HR_BREAK(hr);
tagDublicatorMonitorInfo curMonInfo;
hr = DXGICaptureHelper::ConvertDxgiOutputToMonitorInfo(&dgixOutputDesc, rendererInfo.MonitorIdx, &curMonInfo);
CHECK_HR_BREAK(hr);
if (!DXGICaptureHelper::IsEqualMonitorInfo(pSelectedMonitorInfo, &curMonInfo)) {
hr = E_INVALIDARG; // Monitor settings have changed ???
break;
}
// QI for Output 1
CComPtr<IDXGIOutput1> ipDxgiOutput1;
hr = ipDxgiOutput->QueryInterface(IID_PPV_ARGS(&ipDxgiOutput1));
CHECK_HR_BREAK(hr);
// Create desktop duplication
hr = ipDxgiOutput1->DuplicateOutput(m_ipD3D11Device, &ipDxgiOutputDuplication);
CHECK_HR_BREAK(hr);
DXGI_OUTDUPL_DESC dxgiOutputDuplDesc;
ipDxgiOutputDuplication->GetDesc(&dxgiOutputDuplDesc);
hr = DXGICaptureHelper::CalculateRendererInfo(&dxgiOutputDuplDesc, &rendererInfo);
CHECK_HR_BREAK(hr);
// Create CPU access texture
D3D11_TEXTURE2D_DESC desc;
desc.Width = rendererInfo.SrcBounds.Width;
desc.Height = rendererInfo.SrcBounds.Height;
desc.Format = rendererInfo.SrcFormat;
desc.ArraySize = 1;
desc.BindFlags = 0;
desc.MiscFlags = 0;
desc.SampleDesc.Count = 1;
desc.SampleDesc.Quality = 0;
desc.MipLevels = 1;
desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ | D3D11_CPU_ACCESS_WRITE;
desc.Usage = D3D11_USAGE_STAGING;
hr = m_ipD3D11Device->CreateTexture2D(&desc, NULL, &ipCopyTexture2D);
CHECK_HR_BREAK(hr);
if (nullptr == ipCopyTexture2D)
{
hr = E_OUTOFMEMORY;
break;
}
#pragma region <For_2D_operations>
// Create D2D1 device
UINT uiFlags = m_ipD3D11Device->GetCreationFlags();
D2D1_CREATION_PROPERTIES d2d1Props = D2D1::CreationProperties
(
(uiFlags & D3D11_CREATE_DEVICE_SINGLETHREADED)
? D2D1_THREADING_MODE_SINGLE_THREADED
: D2D1_THREADING_MODE_MULTI_THREADED,
D2D1_DEBUG_LEVEL_NONE,
(uiFlags & D3D11_CREATE_DEVICE_SINGLETHREADED)
? D2D1_DEVICE_CONTEXT_OPTIONS_NONE
: D2D1_DEVICE_CONTEXT_OPTIONS_ENABLE_MULTITHREADED_OPTIMIZATIONS
);
hr = D2D1CreateDevice(ipDxgiDevice, d2d1Props, &ipD2D1Device);
CHECK_HR_BREAK(hr);
// Get D2D1 factory
ipD2D1Device->GetFactory(&ipD2D1Factory);
if (nullptr == ipD2D1Factory)
{
hr = D2DERR_INVALID_CALL;
break;
}
//create WIC factory
hr = CoCreateInstance(
CLSID_WICImagingFactory,
NULL,
CLSCTX_INPROC_SERVER,
IID_IWICImagingFactory,
reinterpret_cast<void **>(&ipWICImageFactory)
);
CHECK_HR_BREAK(hr);
// create D2D1 target bitmap for render
hr = ipWICImageFactory->CreateBitmap(
(UINT)rendererInfo.OutputSize.Width,
(UINT)rendererInfo.OutputSize.Height,
GUID_WICPixelFormat32bppPBGRA,
WICBitmapCacheOnDemand,
&ipWICOutputBitmap);
CHECK_HR_BREAK(hr);
if (nullptr == ipWICOutputBitmap)
{
hr = E_OUTOFMEMORY;
break;
}
// create a D2D1 render target (for D2D1 drawing)
D2D1_RENDER_TARGET_PROPERTIES d2d1RenderTargetProp = D2D1::RenderTargetProperties
(
D2D1_RENDER_TARGET_TYPE_DEFAULT,
D2D1::PixelFormat(DXGI_FORMAT_B8G8R8A8_UNORM, D2D1_ALPHA_MODE_PREMULTIPLIED),
0.0f, // default dpi
0.0f, // default dpi
D2D1_RENDER_TARGET_USAGE_GDI_COMPATIBLE
);
hr = ipD2D1Factory->CreateWicBitmapRenderTarget(
ipWICOutputBitmap,
d2d1RenderTargetProp,
&ipD2D1RenderTarget
);
CHECK_HR_BREAK(hr);
#pragma endregion </For_2D_operations>
} while (false);
if (SUCCEEDED(hr))
{
// copy output parameters
memcpy_s((void*)&m_rendererInfo, sizeof(m_rendererInfo), (const void*)&rendererInfo, sizeof(m_rendererInfo));
// set parameters
m_desktopOutputDesc = dgixOutputDesc;
m_ipDxgiOutputDuplication = ipDxgiOutputDuplication;
m_ipCopyTexture2D = ipCopyTexture2D;
m_ipD2D1Device = ipD2D1Device;
m_ipD2D1Factory = ipD2D1Factory;
m_ipWICImageFactory = ipWICImageFactory;
m_ipWICOutputBitmap = ipWICOutputBitmap;
m_ipD2D1RenderTarget = ipD2D1RenderTarget;
}
return S_OK;
}
void CDXGICapture::terminateDeviceResource()
{
m_ipDxgiOutputDuplication = nullptr;
m_ipCopyTexture2D = nullptr;
m_ipD2D1Device = nullptr;
m_ipD2D1Factory = nullptr;
m_ipWICImageFactory = nullptr;
m_ipWICOutputBitmap = nullptr;
m_ipD2D1RenderTarget = nullptr;
// clear config parameters
RtlZeroMemory(&m_rendererInfo, sizeof(m_rendererInfo));
// clear mouse information parameters
if (m_mouseInfo.PtrShapeBuffer != nullptr) {
delete[] m_mouseInfo.PtrShapeBuffer;
m_mouseInfo.PtrShapeBuffer = nullptr;
}
RtlZeroMemory(&m_mouseInfo, sizeof(m_mouseInfo));
// clear temp temp buffer
if (m_tempMouseBuffer.Buffer != nullptr) {
delete[] m_tempMouseBuffer.Buffer;
m_tempMouseBuffer.Buffer = nullptr;
}
RtlZeroMemory(&m_tempMouseBuffer, sizeof(m_tempMouseBuffer));
// clear desktop output desc
RtlZeroMemory(&m_desktopOutputDesc, sizeof(m_desktopOutputDesc));
}
HRESULT CDXGICapture::Initialize()
{
AUTOLOCK();
if (m_bInitialized) {
return HRESULT_FROM_WIN32(ERROR_ALREADY_INITIALIZED); // already initialized
}
HRESULT hr = S_OK;
D3D_FEATURE_LEVEL lFeatureLevel;
CComPtr<ID3D11Device> ipDevice;
CComPtr<ID3D11DeviceContext> ipDeviceContext;
// required for monitor dpi problem (???)
SetProcessDpiAwareness(PROCESS_PER_MONITOR_DPI_AWARE);
// Create device
for (UINT i = 0; i < g_NumDriverTypes; ++i)
{
hr = D3D11CreateDevice(
nullptr,
g_DriverTypes[i],
nullptr,
/* D3D11_CREATE_DEVICE_BGRA_SUPPORT
* This flag adds support for surfaces with a different
* color channel ordering than the API default.
* You need it for compatibility with Direct2D. */
D3D11_CREATE_DEVICE_BGRA_SUPPORT,
g_FeatureLevels,
g_NumFeatureLevels,
D3D11_SDK_VERSION,
&ipDevice,
&lFeatureLevel,
&ipDeviceContext);
if (SUCCEEDED(hr))
{
// Device creation success, no need to loop anymore
break;
}
ipDevice = nullptr;
ipDeviceContext = nullptr;
}
if (FAILED(hr)) {
return hr;
}
if (nullptr == ipDevice) {
return E_UNEXPECTED;
}
// load all monitor informations
hr = loadMonitorInfos(ipDevice);
if (FAILED(hr)) {
return hr;
}
// set common fields
m_lD3DFeatureLevel = lFeatureLevel;
m_ipD3D11Device = ipDevice;
m_ipD3D11DeviceContext = ipDeviceContext;
m_bInitialized = TRUE;
return S_OK;
}
HRESULT CDXGICapture::Terminate()
{
AUTOLOCK();
if (!m_bInitialized) {
return S_FALSE; // already terminated
}
this->terminateDeviceResource();
m_ipD3D11Device = nullptr;
m_ipD3D11DeviceContext = nullptr;
m_lD3DFeatureLevel = D3D_FEATURE_LEVEL_INVALID;
freeMonitorInfos();
m_bInitialized = FALSE;
return S_OK;
}
HRESULT CDXGICapture::SetConfig(const tagScreenCaptureFilterConfig *pConfig)
{
AUTOLOCK();
if (!m_bInitialized) {
return D2DERR_NOT_INITIALIZED;
}
if (nullptr == pConfig) {
return E_INVALIDARG;
}
// terminate old resources
this->terminateDeviceResource();
HRESULT hr = S_OK;
const tagDublicatorMonitorInfo *pSelectedMonitorInfo = nullptr;
pSelectedMonitorInfo = this->FindDublicatorMonitorInfo(pConfig->MonitorIdx);
if (nullptr == pSelectedMonitorInfo) {
return E_INVALIDARG;
}
hr = this->createDeviceResource(pConfig, pSelectedMonitorInfo);
if (FAILED(hr)) {
return hr;
}
return hr;
}
HRESULT CDXGICapture::SetConfig(const tagScreenCaptureFilterConfig &config)
{
return this->SetConfig(&config);
}
BOOL CDXGICapture::IsInitialized() const
{
AUTOLOCK();
return m_bInitialized;
}
D3D_FEATURE_LEVEL CDXGICapture::GetD3DFeatureLevel() const
{
AUTOLOCK();
return m_lD3DFeatureLevel;
}
int CDXGICapture::GetDublicatorMonitorInfoCount() const
{
AUTOLOCK();
return (int)m_monitorInfos.size();
}
const tagDublicatorMonitorInfo* CDXGICapture::GetDublicatorMonitorInfo(int index) const
{
AUTOLOCK();
size_t nCount = m_monitorInfos.size();
if ((index < 0) || (index >= (int)nCount)) {
return nullptr;
}
return m_monitorInfos[index];
} // GetDublicatorMonitorInfo
const tagDublicatorMonitorInfo* CDXGICapture::FindDublicatorMonitorInfo(int monitorIdx) const
{
AUTOLOCK();
size_t nCount = m_monitorInfos.size();
if (nCount == 0) {
return nullptr;
}
DublicatorMonitorInfoVec::const_iterator it = m_monitorInfos.begin();
DublicatorMonitorInfoVec::const_iterator end = m_monitorInfos.end();
for (size_t i = 0; (i < nCount) && (it != end); i++, it++) {
tagDublicatorMonitorInfo *pInfo = *it;
if (monitorIdx == pInfo->Idx) {
return pInfo;
}
}
return nullptr;
} // FindDublicatorMonitorInfo
//
// CaptureToFile
//
HRESULT CDXGICapture::CaptureToFile(_In_ LPCWSTR lpcwOutputFileName, _Out_opt_ BOOL *pRetIsTimeout /*= NULL*/, _Out_opt_ UINT *pRetRenderDuration /*= NULL*/)
{
AUTOLOCK();
if (nullptr != pRetIsTimeout) {
*pRetIsTimeout = FALSE;
}
if (nullptr != pRetRenderDuration) {
*pRetRenderDuration = 0xFFFFFFFF;
}
if (!m_bInitialized) {
return D2DERR_NOT_INITIALIZED;
}
CHECK_POINTER_EX(m_ipDxgiOutputDuplication, E_INVALIDARG);
CHECK_POINTER_EX(lpcwOutputFileName, E_INVALIDARG);
HRESULT hr = S_OK;
hr = DXGICaptureHelper::IsRendererInfoValid(&m_rendererInfo);
if (FAILED(hr)) {
return hr;
}
// is valid?
hr = DXGICaptureHelper::GetContainerFormatByFileName(lpcwOutputFileName);
if (FAILED(hr)) {
return hr;
}
DXGI_OUTDUPL_FRAME_INFO FrameInfo;
CComPtr<IDXGIResource> ipDesktopResource;
CComPtr<ID3D11Texture2D> ipAcquiredDesktopImage;
CComPtr<ID2D1Bitmap> ipD2D1SourceBitmap;
std::chrono::system_clock::time_point startTick;
if (nullptr != pRetRenderDuration) {
startTick = std::chrono::system_clock::now();
}
// Get new frame
hr = m_ipDxgiOutputDuplication->AcquireNextFrame(1000, &FrameInfo, &ipDesktopResource);
if (hr == DXGI_ERROR_WAIT_TIMEOUT)
{
if (nullptr != pRetIsTimeout) {
*pRetIsTimeout = TRUE;
}
return S_FALSE;
}
else if (FAILED(hr))
{
return hr;
}
// QI for ID3D11Texture2D
hr = ipDesktopResource->QueryInterface(IID_PPV_ARGS(&ipAcquiredDesktopImage));
ipDesktopResource = nullptr;
CHECK_HR_RETURN(hr);
if (nullptr == ipAcquiredDesktopImage)
{
// release frame
m_ipDxgiOutputDuplication->ReleaseFrame();
return E_OUTOFMEMORY;
}
// Copy needed full part of desktop image
m_ipD3D11DeviceContext->CopyResource(m_ipCopyTexture2D, ipAcquiredDesktopImage);
if (m_rendererInfo.ShowCursor) {
hr = DXGICaptureHelper::GetMouse(m_ipDxgiOutputDuplication, &m_mouseInfo, &FrameInfo, (UINT)m_rendererInfo.MonitorIdx, m_desktopOutputDesc.DesktopCoordinates.left, m_desktopOutputDesc.DesktopCoordinates.top);
if (SUCCEEDED(hr) && m_mouseInfo.Visible) {
hr = DXGICaptureHelper::DrawMouse(&m_mouseInfo, &m_desktopOutputDesc, &m_tempMouseBuffer, m_ipCopyTexture2D);
}
if (FAILED(hr)) {
// release frame
m_ipDxgiOutputDuplication->ReleaseFrame();
return hr;
}
}
// release frame
hr = m_ipDxgiOutputDuplication->ReleaseFrame();
CHECK_HR_RETURN(hr);
// create D2D1 source bitmap
hr = DXGICaptureHelper::CreateBitmap(m_ipD2D1RenderTarget, m_ipCopyTexture2D, &ipD2D1SourceBitmap);
CHECK_HR_RETURN(hr);
D2D1_RECT_F rcSource = D2D1::RectF(
(FLOAT)m_rendererInfo.SrcBounds.X,
(FLOAT)m_rendererInfo.SrcBounds.Y,
(FLOAT)(m_rendererInfo.SrcBounds.X + m_rendererInfo.SrcBounds.Width),
(FLOAT)(m_rendererInfo.SrcBounds.Y + m_rendererInfo.SrcBounds.Height));
D2D1_RECT_F rcTarget = D2D1::RectF(
(FLOAT)m_rendererInfo.DstBounds.X,
(FLOAT)m_rendererInfo.DstBounds.Y,
(FLOAT)(m_rendererInfo.DstBounds.X + m_rendererInfo.DstBounds.Width),
(FLOAT)(m_rendererInfo.DstBounds.Y + m_rendererInfo.DstBounds.Height));
D2D1_POINT_2F ptTransformCenter = D2D1::Point2F(m_rendererInfo.OutputSize.Width / 2.0f, m_rendererInfo.OutputSize.Height / 2.0f);
// Apply the rotation transform to the render target.
D2D1::Matrix3x2F rotate = D2D1::Matrix3x2F::Rotation(
m_rendererInfo.RotationDegrees,
ptTransformCenter
);
D2D1::Matrix3x2F scale = D2D1::Matrix3x2F::Scale(
D2D1::SizeF(m_rendererInfo.ScaleX, m_rendererInfo.ScaleY),
ptTransformCenter
);
// Priority: first rotate, after scale...
m_ipD2D1RenderTarget->SetTransform(rotate * scale);
m_ipD2D1RenderTarget->BeginDraw();
// clear background color
m_ipD2D1RenderTarget->Clear(D2D1::ColorF(D2D1::ColorF::Black, 1.0f));
m_ipD2D1RenderTarget->DrawBitmap(ipD2D1SourceBitmap, rcTarget, 1.0f, D2D1_BITMAP_INTERPOLATION_MODE_LINEAR, rcSource);
// Reset transform
//m_ipD2D1RenderTarget->SetTransform(D2D1::Matrix3x2F::Identity());
// Logo draw sample
//m_ipD2D1RenderTarget->DrawBitmap(ipBmpLogo, D2D1::RectF(0, 0, 2 * 200, 2 * 46));
hr = m_ipD2D1RenderTarget->EndDraw();
if (FAILED(hr)) {
return hr;
}
// calculate render time without save
if (nullptr != pRetRenderDuration) {
*pRetRenderDuration = (UINT)((std::chrono::system_clock::now() - startTick).count() / 10000);
}
hr = DXGICaptureHelper::SaveImageToFile(m_ipWICImageFactory, m_ipWICOutputBitmap, lpcwOutputFileName);
if (FAILED(hr)) {
return hr;
}
return S_OK;
} // CaptureToFile
#undef AUTOLOCK

View File

@ -0,0 +1,92 @@
/*****************************************************************************
* DXGICapture.h
*
* Copyright (C) 2020 Gokhan Erdogdu <gokhan_erdogdu - at - yahoo - dot - com>
*
* DXGICapture is free software; you can redistribute it and/or modify it under
* the terms of the GNU Lesser General Public License as published by the Free
* Software Foundation; either version 2.1 of the License, or (at your option)
* any later version.
*
* DXGICapture 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 Lesser General Public License for more
* details.
*
******************************************************************************/
#pragma once
#ifndef __DXGICAPTURE_H__
#define __DXGICAPTURE_H__
#include <atlbase.h>
#include <ShellScalingAPI.h>
#include <dxgi1_2.h>
#include <d3d11.h>
#include <d2d1.h>
#include <d2d1_1.h> // for ID2D1Effect
#include <wincodec.h>
#include "DXGICaptureTypes.h"
#define D3D_FEATURE_LEVEL_INVALID ((D3D_FEATURE_LEVEL)0x0)
class CDXGICapture
{
private:
ATL::CComAutoCriticalSection m_csLock;
BOOL m_bInitialized;
DublicatorMonitorInfoVec m_monitorInfos;
tagRendererInfo m_rendererInfo;
tagMouseInfo m_mouseInfo;
tagFrameBufferInfo m_tempMouseBuffer;
DXGI_OUTPUT_DESC m_desktopOutputDesc;
D3D_FEATURE_LEVEL m_lD3DFeatureLevel;
CComPtr<ID3D11Device> m_ipD3D11Device;
CComPtr<ID3D11DeviceContext> m_ipD3D11DeviceContext;
CComPtr<IDXGIOutputDuplication> m_ipDxgiOutputDuplication;
CComPtr<ID3D11Texture2D> m_ipCopyTexture2D;
CComPtr<ID2D1Device> m_ipD2D1Device;
CComPtr<ID2D1Factory> m_ipD2D1Factory;
CComPtr<IWICImagingFactory> m_ipWICImageFactory;
CComPtr<IWICBitmap> m_ipWICOutputBitmap;
CComPtr<ID2D1RenderTarget> m_ipD2D1RenderTarget;
public:
CDXGICapture();
~CDXGICapture();
private:
HRESULT loadMonitorInfos(ID3D11Device *pDevice);
void freeMonitorInfos();
HRESULT createDeviceResource(
const tagScreenCaptureFilterConfig *pConfig,
const tagDublicatorMonitorInfo *pSelectedMonitorInfo);
void terminateDeviceResource();
public:
HRESULT Initialize();
HRESULT Terminate();
HRESULT SetConfig(const tagScreenCaptureFilterConfig *pConfig);
HRESULT SetConfig(const tagScreenCaptureFilterConfig &config);
BOOL IsInitialized() const;
D3D_FEATURE_LEVEL GetD3DFeatureLevel() const;
int GetDublicatorMonitorInfoCount() const;
const tagDublicatorMonitorInfo* GetDublicatorMonitorInfo(int index) const;
const tagDublicatorMonitorInfo* FindDublicatorMonitorInfo(int monitorIdx) const;
HRESULT CaptureToFile(_In_ LPCWSTR lpcwOutputFileName, _Out_opt_ BOOL *pRetIsTimeout = NULL, _Out_opt_ UINT *pRetRenderDuration = NULL);
};
#endif // __DXGICAPTURE_H__

View File

@ -0,0 +1,960 @@
/*****************************************************************************
* DXGICaptureHelper.h
*
* Copyright (C) 2020 Gokhan Erdogdu <gokhan_erdogdu - at - yahoo - dot - com>
*
* DXGICapture is free software; you can redistribute it and/or modify it under
* the terms of the GNU Lesser General Public License as published by the Free
* Software Foundation; either version 2.1 of the License, or (at your option)
* any later version.
*
* DXGICapture 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 Lesser General Public License for more
* details.
*
******************************************************************************/
#pragma once
#ifndef __DXGICAPTUREHELPER_H__
#define __DXGICAPTUREHELPER_H__
#include <atlbase.h>
#include <Shlwapi.h>
#include <dxgi1_2.h>
#include <d3d11.h>
#include <d2d1.h>
#include <wincodec.h>
#include "DXGICaptureTypes.h"
#pragma comment (lib, "Shlwapi.lib")
//
// class DXGICaptureHelper
//
class DXGICaptureHelper
{
public:
static
COM_DECLSPEC_NOTHROW
inline
HRESULT
ConvertDxgiOutputToMonitorInfo(
_In_ const DXGI_OUTPUT_DESC *pDxgiOutput,
_In_ int monitorIdx,
_Out_ tagDublicatorMonitorInfo *pOutVal
)
{
CHECK_POINTER(pOutVal);
// reset output parameter
RtlZeroMemory(pOutVal, sizeof(tagDublicatorMonitorInfo));
CHECK_POINTER_EX(pDxgiOutput, E_INVALIDARG);
switch (pDxgiOutput->Rotation)
{
case DXGI_MODE_ROTATION_UNSPECIFIED:
case DXGI_MODE_ROTATION_IDENTITY:
pOutVal->RotationDegrees = 0;
break;
case DXGI_MODE_ROTATION_ROTATE90:
pOutVal->RotationDegrees = 90;
break;
case DXGI_MODE_ROTATION_ROTATE180:
pOutVal->RotationDegrees = 180;
break;
case DXGI_MODE_ROTATION_ROTATE270:
pOutVal->RotationDegrees = 270;
break;
}
pOutVal->Idx = monitorIdx;
pOutVal->Bounds.X = pDxgiOutput->DesktopCoordinates.left;
pOutVal->Bounds.Y = pDxgiOutput->DesktopCoordinates.top;
pOutVal->Bounds.Width = pDxgiOutput->DesktopCoordinates.right - pDxgiOutput->DesktopCoordinates.left;
pOutVal->Bounds.Height = pDxgiOutput->DesktopCoordinates.bottom - pDxgiOutput->DesktopCoordinates.top;
wsprintfW(pOutVal->DisplayName, L"Display %d: %ldx%ld @ %ld,%ld"
, monitorIdx + 1
, pOutVal->Bounds.Width, pOutVal->Bounds.Height
, pOutVal->Bounds.X, pOutVal->Bounds.Y);
return S_OK;
} // ConvertDxgiOutputToMonitorInfo
static
COM_DECLSPEC_NOTHROW
inline
BOOL
IsEqualMonitorInfo(
_In_ const tagDublicatorMonitorInfo *p1,
_In_ const tagDublicatorMonitorInfo *p2
)
{
if (nullptr == p1) {
return (nullptr == p2);
}
if (nullptr == p2) {
return FALSE;
}
return memcmp((const void*)p1, (const void*)p2, sizeof(tagDublicatorMonitorInfo)) == 0;
} // IsEqualMonitorInfo
static
COM_DECLSPEC_NOTHROW
inline
HRESULT
IsRendererInfoValid(
_In_ const tagRendererInfo *pRendererInfo
)
{
CHECK_POINTER_EX(pRendererInfo, E_INVALIDARG);
if (pRendererInfo->SrcFormat != DXGI_FORMAT_B8G8R8A8_UNORM) {
return D2DERR_UNSUPPORTED_PIXEL_FORMAT;
}
if (pRendererInfo->SizeMode != tagFrameSizeMode_Normal) {
if ((pRendererInfo->OutputSize.Width <= 0) || (pRendererInfo->OutputSize.Height <= 0)) {
return D2DERR_BITMAP_BOUND_AS_TARGET;
}
}
if ((pRendererInfo->DstBounds.Width <= 0) || (pRendererInfo->DstBounds.Height <= 0) ||
(pRendererInfo->SrcBounds.Width <= 0) || (pRendererInfo->SrcBounds.Height <= 0))
{
return D2DERR_ORIGINAL_TARGET_NOT_BOUND;
}
return S_OK;
}
static
COM_DECLSPEC_NOTHROW
inline
HRESULT
CalculateRendererInfo(
_In_ const DXGI_OUTDUPL_DESC *pDxgiOutputDuplDesc,
_Inout_ tagRendererInfo *pRendererInfo
)
{
CHECK_POINTER_EX(pDxgiOutputDuplDesc, E_INVALIDARG);
CHECK_POINTER_EX(pRendererInfo, E_INVALIDARG);
pRendererInfo->SrcFormat = pDxgiOutputDuplDesc->ModeDesc.Format;
// get rotate state
switch (pDxgiOutputDuplDesc->Rotation)
{
case DXGI_MODE_ROTATION_ROTATE90:
pRendererInfo->RotationDegrees = 90.0f;
pRendererInfo->SrcBounds.X = 0;
pRendererInfo->SrcBounds.Y = 0;
pRendererInfo->SrcBounds.Width = pDxgiOutputDuplDesc->ModeDesc.Height;
pRendererInfo->SrcBounds.Height = pDxgiOutputDuplDesc->ModeDesc.Width;
break;
case DXGI_MODE_ROTATION_ROTATE180:
pRendererInfo->RotationDegrees = 180.0;
pRendererInfo->SrcBounds.X = 0;
pRendererInfo->SrcBounds.Y = 0;
pRendererInfo->SrcBounds.Width = pDxgiOutputDuplDesc->ModeDesc.Width;
pRendererInfo->SrcBounds.Height = pDxgiOutputDuplDesc->ModeDesc.Height;
break;
case DXGI_MODE_ROTATION_ROTATE270:
pRendererInfo->RotationDegrees = 270.0f;
pRendererInfo->SrcBounds.X = 0;
pRendererInfo->SrcBounds.Y = 0;
pRendererInfo->SrcBounds.Width = pDxgiOutputDuplDesc->ModeDesc.Height;
pRendererInfo->SrcBounds.Height = pDxgiOutputDuplDesc->ModeDesc.Width;
break;
default: // OR DXGI_MODE_ROTATION_IDENTITY:
pRendererInfo->RotationDegrees = 0.0f;
pRendererInfo->SrcBounds.X = 0;
pRendererInfo->SrcBounds.Y = 0;
pRendererInfo->SrcBounds.Width = pDxgiOutputDuplDesc->ModeDesc.Width;
pRendererInfo->SrcBounds.Height = pDxgiOutputDuplDesc->ModeDesc.Height;
break;
}
// force rotate
switch (pRendererInfo->RotationMode)
{
case tagFrameRotationMode::tagFrameRotationMode_Identity:
pRendererInfo->RotationDegrees = 0.0f;
break;
case tagFrameRotationMode::tagFrameRotationMode_90:
pRendererInfo->RotationDegrees = 90.0f;
break;
case tagFrameRotationMode::tagFrameRotationMode_180:
pRendererInfo->RotationDegrees = 180.0f;
break;
case tagFrameRotationMode::tagFrameRotationMode_270:
pRendererInfo->RotationDegrees = 270.0f;
break;
default: // tagFrameRotationMode::tagFrameRotationMode_Auto
break;
}
if (pRendererInfo->SizeMode == tagFrameSizeMode_Zoom)
{
FLOAT fSrcAspect, fOutAspect, fScaleFactor;
// center for output
pRendererInfo->DstBounds.Width = pRendererInfo->SrcBounds.Width;
pRendererInfo->DstBounds.Height = pRendererInfo->SrcBounds.Height;
pRendererInfo->DstBounds.X = (pRendererInfo->OutputSize.Width - pRendererInfo->SrcBounds.Width) >> 1;
pRendererInfo->DstBounds.Y = (pRendererInfo->OutputSize.Height - pRendererInfo->SrcBounds.Height) >> 1;
fOutAspect = (FLOAT)pRendererInfo->OutputSize.Width / pRendererInfo->OutputSize.Height;
if ((pRendererInfo->RotationDegrees == 0.0f) || (pRendererInfo->RotationDegrees == 180.0f))
{
fSrcAspect = (FLOAT)pRendererInfo->SrcBounds.Width / pRendererInfo->SrcBounds.Height;
if (fSrcAspect > fOutAspect)
{
fScaleFactor = (FLOAT)pRendererInfo->OutputSize.Width / pRendererInfo->SrcBounds.Width;
}
else
{
fScaleFactor = (FLOAT)pRendererInfo->OutputSize.Height / pRendererInfo->SrcBounds.Height;
}
}
else // 90 or 270 degree
{
fSrcAspect = (FLOAT)pRendererInfo->SrcBounds.Height / pRendererInfo->SrcBounds.Width;
if (fSrcAspect > fOutAspect)
{
fScaleFactor = (FLOAT)pRendererInfo->OutputSize.Width / pRendererInfo->SrcBounds.Height;
}
else
{
fScaleFactor = (FLOAT)pRendererInfo->OutputSize.Height / pRendererInfo->SrcBounds.Width;
}
}
pRendererInfo->ScaleX = fScaleFactor;
pRendererInfo->ScaleY = fScaleFactor;
}
else if (pRendererInfo->SizeMode == tagFrameSizeMode_CenterImage)
{
// center for output
pRendererInfo->DstBounds.Width = pRendererInfo->SrcBounds.Width;
pRendererInfo->DstBounds.Height = pRendererInfo->SrcBounds.Height;
pRendererInfo->DstBounds.X = (pRendererInfo->OutputSize.Width - pRendererInfo->SrcBounds.Width) >> 1;
pRendererInfo->DstBounds.Y = (pRendererInfo->OutputSize.Height - pRendererInfo->SrcBounds.Height) >> 1;
}
else if (pRendererInfo->SizeMode == tagFrameSizeMode_AutoSize)
{
// set the destination bounds
pRendererInfo->DstBounds.Width = pRendererInfo->SrcBounds.Width;
pRendererInfo->DstBounds.Height = pRendererInfo->SrcBounds.Height;
if ((pRendererInfo->RotationDegrees == 0.0f) || (pRendererInfo->RotationDegrees == 180.0f))
{
// same as the source size
pRendererInfo->OutputSize.Width = pRendererInfo->SrcBounds.Width;
pRendererInfo->OutputSize.Height = pRendererInfo->SrcBounds.Height;
}
else // 90 or 270 degree
{
// same as the source size
pRendererInfo->OutputSize.Width = pRendererInfo->SrcBounds.Height;
pRendererInfo->OutputSize.Height = pRendererInfo->SrcBounds.Width;
// center for output
pRendererInfo->DstBounds.X = (pRendererInfo->OutputSize.Width - pRendererInfo->SrcBounds.Width) >> 1;
pRendererInfo->DstBounds.Y = (pRendererInfo->OutputSize.Height - pRendererInfo->SrcBounds.Height) >> 1;
}
}
else if (pRendererInfo->SizeMode == tagFrameSizeMode_StretchImage)
{
// center for output
pRendererInfo->DstBounds.Width = pRendererInfo->SrcBounds.Width;
pRendererInfo->DstBounds.Height = pRendererInfo->SrcBounds.Height;
pRendererInfo->DstBounds.X = (pRendererInfo->OutputSize.Width - pRendererInfo->SrcBounds.Width) >> 1;
pRendererInfo->DstBounds.Y = (pRendererInfo->OutputSize.Height - pRendererInfo->SrcBounds.Height) >> 1;
if ((pRendererInfo->RotationDegrees == 0.0f) || (pRendererInfo->RotationDegrees == 180.0f))
{
pRendererInfo->ScaleX = (FLOAT)pRendererInfo->OutputSize.Width / pRendererInfo->DstBounds.Width;
pRendererInfo->ScaleY = (FLOAT)pRendererInfo->OutputSize.Height / pRendererInfo->DstBounds.Height;
}
else // 90 or 270 degree
{
pRendererInfo->ScaleX = (FLOAT)pRendererInfo->OutputSize.Width / pRendererInfo->DstBounds.Height;
pRendererInfo->ScaleY = (FLOAT)pRendererInfo->OutputSize.Height / pRendererInfo->DstBounds.Width;
}
}
else // tagFrameSizeMode_Normal
{
pRendererInfo->DstBounds.Width = pRendererInfo->SrcBounds.Width;
pRendererInfo->DstBounds.Height = pRendererInfo->SrcBounds.Height;
if (pRendererInfo->RotationDegrees == 90)
{
// set destination origin (bottom-left)
pRendererInfo->DstBounds.X = (pRendererInfo->OutputSize.Width - pRendererInfo->OutputSize.Height) >> 1;
pRendererInfo->DstBounds.Y = ((pRendererInfo->OutputSize.Width + pRendererInfo->OutputSize.Height) >> 1) - pRendererInfo->DstBounds.Height;
}
else if (pRendererInfo->RotationDegrees == 180.0f)
{
// set destination origin (bottom-right)
pRendererInfo->DstBounds.X = pRendererInfo->OutputSize.Width - pRendererInfo->DstBounds.Width;
pRendererInfo->DstBounds.Y = pRendererInfo->OutputSize.Height - pRendererInfo->DstBounds.Height;
}
else if (pRendererInfo->RotationDegrees == 270)
{
// set destination origin (top-right)
pRendererInfo->DstBounds.Y = (pRendererInfo->OutputSize.Height - pRendererInfo->OutputSize.Width) >> 1;
pRendererInfo->DstBounds.X = pRendererInfo->OutputSize.Width - pRendererInfo->DstBounds.Width - ((pRendererInfo->OutputSize.Width - pRendererInfo->OutputSize.Height) >> 1);
}
}
return S_OK;
}
static
COM_DECLSPEC_NOTHROW
inline
HRESULT
ResizeFrameBuffer(
_Inout_ tagFrameBufferInfo *pBufferInfo,
_In_ UINT uiNewSize
)
{
CHECK_POINTER(pBufferInfo);
if (uiNewSize <= pBufferInfo->BufferSize)
{
return S_FALSE; // no change
}
if (nullptr != pBufferInfo->Buffer) {
delete[] pBufferInfo->Buffer;
pBufferInfo->Buffer = nullptr;
}
pBufferInfo->Buffer = new (std::nothrow) BYTE[uiNewSize];
if (!(pBufferInfo->Buffer))
{
pBufferInfo->BufferSize = 0;
return E_OUTOFMEMORY;
}
pBufferInfo->BufferSize = uiNewSize;
return S_OK;
} // ResizeFrameBuffer
static
COM_DECLSPEC_NOTHROW
inline
HRESULT
GetMouse(
_In_ IDXGIOutputDuplication *pOutputDuplication,
_Inout_ tagMouseInfo *PtrInfo,
_In_ DXGI_OUTDUPL_FRAME_INFO *FrameInfo,
UINT MonitorIdx,
INT OffsetX,
INT OffsetY
)
{
CHECK_POINTER_EX(pOutputDuplication, E_INVALIDARG);
CHECK_POINTER_EX(PtrInfo, E_INVALIDARG);
CHECK_POINTER_EX(FrameInfo, E_INVALIDARG);
// A non-zero mouse update timestamp indicates that there is a mouse position update and optionally a shape change
if (FrameInfo->LastMouseUpdateTime.QuadPart == 0)
{
return S_OK;
}
bool UpdatePosition = true;
// Make sure we don't update pointer position wrongly
// If pointer is invisible, make sure we did not get an update from another output that the last time that said pointer
// was visible, if so, don't set it to invisible or update.
if (!FrameInfo->PointerPosition.Visible && (PtrInfo->WhoUpdatedPositionLast != MonitorIdx))
{
UpdatePosition = false;
}
// If two outputs both say they have a visible, only update if new update has newer timestamp
if (FrameInfo->PointerPosition.Visible && PtrInfo->Visible && (PtrInfo->WhoUpdatedPositionLast != MonitorIdx) && (PtrInfo->LastTimeStamp.QuadPart > FrameInfo->LastMouseUpdateTime.QuadPart))
{
UpdatePosition = false;
}
// Update position
if (UpdatePosition)
{
PtrInfo->Position.x = FrameInfo->PointerPosition.Position.x - OffsetX;
PtrInfo->Position.y = FrameInfo->PointerPosition.Position.y - OffsetY;
PtrInfo->WhoUpdatedPositionLast = MonitorIdx;
PtrInfo->LastTimeStamp = FrameInfo->LastMouseUpdateTime;
PtrInfo->Visible = FrameInfo->PointerPosition.Visible != 0;
}
// No new shape
if (FrameInfo->PointerShapeBufferSize == 0)
{
return S_OK;
}
// Old buffer too small
if (FrameInfo->PointerShapeBufferSize > PtrInfo->ShapeBufferSize)
{
if (PtrInfo->PtrShapeBuffer != nullptr)
{
delete[] PtrInfo->PtrShapeBuffer;
PtrInfo->PtrShapeBuffer = nullptr;
}
PtrInfo->PtrShapeBuffer = new (std::nothrow) BYTE[FrameInfo->PointerShapeBufferSize];
if (PtrInfo->PtrShapeBuffer == nullptr)
{
PtrInfo->ShapeBufferSize = 0;
return E_OUTOFMEMORY;
}
// Update buffer size
PtrInfo->ShapeBufferSize = FrameInfo->PointerShapeBufferSize;
}
// Get shape
UINT BufferSizeRequired;
HRESULT hr = pOutputDuplication->GetFramePointerShape(
FrameInfo->PointerShapeBufferSize,
reinterpret_cast<VOID*>(PtrInfo->PtrShapeBuffer),
&BufferSizeRequired,
&(PtrInfo->ShapeInfo)
);
if (FAILED(hr))
{
delete[] PtrInfo->PtrShapeBuffer;
PtrInfo->PtrShapeBuffer = nullptr;
PtrInfo->ShapeBufferSize = 0;
return hr;
}
return S_OK;
} // GetMouse
static
COM_DECLSPEC_NOTHROW
inline
HRESULT
ProcessMouseMask(
_In_ const tagMouseInfo *PtrInfo,
_In_ const DXGI_OUTPUT_DESC *DesktopDesc,
_Inout_ tagFrameBufferInfo *pBufferInfo
)
{
CHECK_POINTER_EX(PtrInfo, E_INVALIDARG);
CHECK_POINTER_EX(DesktopDesc, E_INVALIDARG);
CHECK_POINTER_EX(pBufferInfo, E_INVALIDARG);
if (!PtrInfo->Visible) {
return S_FALSE;
}
HRESULT hr = S_OK;
INT DesktopWidth = (INT)(DesktopDesc->DesktopCoordinates.right - DesktopDesc->DesktopCoordinates.left);
INT DesktopHeight = (INT)(DesktopDesc->DesktopCoordinates.bottom - DesktopDesc->DesktopCoordinates.top);
pBufferInfo->Bounds.X = PtrInfo->Position.x;
pBufferInfo->Bounds.Y = PtrInfo->Position.y;
pBufferInfo->Bounds.Width = PtrInfo->ShapeInfo.Width;
pBufferInfo->Bounds.Height = (PtrInfo->ShapeInfo.Type == DXGI_OUTDUPL_POINTER_SHAPE_TYPE_MONOCHROME)
? (INT)(PtrInfo->ShapeInfo.Height / 2)
: (INT)PtrInfo->ShapeInfo.Height;
pBufferInfo->Pitch = pBufferInfo->Bounds.Width * 4;
switch (PtrInfo->ShapeInfo.Type)
{
case DXGI_OUTDUPL_POINTER_SHAPE_TYPE_COLOR:
{
// Resize mouseshape buffer (if necessary)
hr = DXGICaptureHelper::ResizeFrameBuffer(pBufferInfo, PtrInfo->ShapeBufferSize);
if (FAILED(hr)) {
return hr;
}
// use current mouseshape buffer
// Copy mouseshape buffer
memcpy_s((void*)pBufferInfo->Buffer, pBufferInfo->BufferSize, (const void*)PtrInfo->PtrShapeBuffer, PtrInfo->ShapeBufferSize);
break;
}
case DXGI_OUTDUPL_POINTER_SHAPE_TYPE_MONOCHROME:
{
// Resize mouseshape buffer (if necessary)
hr = DXGICaptureHelper::ResizeFrameBuffer(pBufferInfo, pBufferInfo->Bounds.Height * pBufferInfo->Pitch);
if (FAILED(hr)) {
return hr;
}
UINT* InitBuffer32 = reinterpret_cast<UINT*>(pBufferInfo->Buffer);
for (INT Row = 0; Row < pBufferInfo->Bounds.Height; ++Row)
{
// Set mask
BYTE Mask = 0x80;
for (INT Col = 0; Col < pBufferInfo->Bounds.Width; ++Col)
{
BYTE XorMask = PtrInfo->PtrShapeBuffer[(Col / 8) + ((Row + (PtrInfo->ShapeInfo.Height / 2)) * (PtrInfo->ShapeInfo.Pitch))] & Mask;
// Set new pixel
InitBuffer32[(Row * pBufferInfo->Bounds.Width) + Col] = (XorMask) ? 0xFFFFFFFF : 0x00000000;
// Adjust mask
if (Mask == 0x01)
{
Mask = 0x80;
}
else
{
Mask = Mask >> 1;
}
}
}
break;
}
case DXGI_OUTDUPL_POINTER_SHAPE_TYPE_MASKED_COLOR:
{
// Resize mouseshape buffer (if necessary)
hr = DXGICaptureHelper::ResizeFrameBuffer(pBufferInfo, pBufferInfo->Bounds.Height * pBufferInfo->Pitch);
if (FAILED(hr)) {
return hr;
}
UINT* InitBuffer32 = reinterpret_cast<UINT*>(pBufferInfo->Buffer);
UINT* ShapeBuffer32 = reinterpret_cast<UINT*>(PtrInfo->PtrShapeBuffer);
for (INT Row = 0; Row < pBufferInfo->Bounds.Height; ++Row)
{
for (INT Col = 0; Col < pBufferInfo->Bounds.Width; ++Col)
{
InitBuffer32[(Row * pBufferInfo->Bounds.Width) + Col] = ShapeBuffer32[Col + (Row * (PtrInfo->ShapeInfo.Pitch / sizeof(UINT)))] | 0xFF000000;
}
}
break;
}
default:
return E_INVALIDARG;
}
UINT* InitBuffer32 = reinterpret_cast<UINT*>(pBufferInfo->Buffer);
UINT width = (UINT)pBufferInfo->Bounds.Width;
UINT height = (UINT)pBufferInfo->Bounds.Height;
switch (DesktopDesc->Rotation)
{
case DXGI_MODE_ROTATION_ROTATE90:
{
// Rotate -90 or +270
for (UINT i = 0; i < width; i++)
{
for (UINT j = 0; j < height; j++)
{
UINT I = j;
UINT J = width - 1 - i;
while ((i*height + j) >(I*width + J))
{
UINT p = I*width + J;
UINT tmp_i = p / height;
UINT tmp_j = p % height;
I = tmp_j;
J = width - 1 - tmp_i;
}
std::swap(*(InitBuffer32 + (i*height + j)), *(InitBuffer32 + (I*width + J)));
}
}
// translate bounds
std::swap(pBufferInfo->Bounds.Width, pBufferInfo->Bounds.Height);
INT nX = pBufferInfo->Bounds.Y;
INT nY = DesktopWidth - (INT)(pBufferInfo->Bounds.X + pBufferInfo->Bounds.Height);
pBufferInfo->Bounds.X = nX;
pBufferInfo->Bounds.Y = nY;
pBufferInfo->Pitch = pBufferInfo->Bounds.Width * 4;
} break;
case DXGI_MODE_ROTATION_ROTATE180:
{
// Rotate -180 or +180
if (height % 2 != 0)
{
//If N is odd reverse the middle row in the matrix
UINT j = height >> 1;
for (UINT i = 0; i < (width >> 1); i++)
{
std::swap(InitBuffer32[j * width + i], InitBuffer32[j * width + width - i - 1]);
}
}
for (UINT j = 0; j < (height >> 1); j++)
{
for (UINT i = 0; i < width; i++)
{
std::swap(InitBuffer32[j * width + i], InitBuffer32[(height - j - 1) * width + width - i - 1]);
}
}
// translate position
INT nX = DesktopWidth - (INT)(pBufferInfo->Bounds.X + pBufferInfo->Bounds.Width);
INT nY = DesktopHeight - (INT)(pBufferInfo->Bounds.Y + pBufferInfo->Bounds.Height);
pBufferInfo->Bounds.X = nX;
pBufferInfo->Bounds.Y = nY;
} break;
case DXGI_MODE_ROTATION_ROTATE270:
{
// Rotate -270 or +90
for (UINT i = 0; i < width; i++)
{
for (UINT j = 0; j < height; j++)
{
UINT I = height - 1 - j;
UINT J = i;
while ((i*height + j) >(I*width + J))
{
int p = I*width + J;
int tmp_i = p / height;
int tmp_j = p % height;
I = height - 1 - tmp_j;
J = tmp_i;
}
std::swap(*(InitBuffer32 + (i*height + j)), *(InitBuffer32 + (I*width + J)));
}
}
// translate bounds
std::swap(pBufferInfo->Bounds.Width, pBufferInfo->Bounds.Height);
INT nX = DesktopHeight - (pBufferInfo->Bounds.Y + pBufferInfo->Bounds.Width);
INT nY = pBufferInfo->Bounds.X;
pBufferInfo->Bounds.X = nX;
pBufferInfo->Bounds.Y = nY;
pBufferInfo->Pitch = pBufferInfo->Bounds.Width * 4;
} break;
}
return S_OK;
} // ProcessMouseMask
//
// Draw mouse provided in buffer to backbuffer
//
static
COM_DECLSPEC_NOTHROW
inline
HRESULT
DrawMouse(
_In_ tagMouseInfo *PtrInfo,
_In_ const DXGI_OUTPUT_DESC *DesktopDesc,
_Inout_ tagFrameBufferInfo *pTempMouseBuffer,
_Inout_ ID3D11Texture2D *pSharedSurf
)
{
CHECK_POINTER_EX(PtrInfo, E_INVALIDARG);
CHECK_POINTER_EX(DesktopDesc, E_INVALIDARG);
CHECK_POINTER_EX(pTempMouseBuffer, E_INVALIDARG);
CHECK_POINTER_EX(pSharedSurf, E_INVALIDARG);
HRESULT hr = S_OK;
D3D11_TEXTURE2D_DESC FullDesc;
pSharedSurf->GetDesc(&FullDesc);
INT SurfWidth = FullDesc.Width;
INT SurfHeight = FullDesc.Height;
INT SurfPitch = FullDesc.Width * 4;
hr = DXGICaptureHelper::ProcessMouseMask(PtrInfo, DesktopDesc, pTempMouseBuffer);
if (FAILED(hr)) {
return hr;
}
// Buffer used if necessary (in case of monochrome or masked pointer)
BYTE* InitBuffer = pTempMouseBuffer->Buffer;
// Clipping adjusted coordinates / dimensions
INT PtrWidth = (INT)pTempMouseBuffer->Bounds.Width;
INT PtrHeight = (INT)pTempMouseBuffer->Bounds.Height;
INT PtrLeft = (INT)pTempMouseBuffer->Bounds.X;
INT PtrTop = (INT)pTempMouseBuffer->Bounds.Y;
INT PtrPitch = (INT)pTempMouseBuffer->Pitch;
INT SrcLeft = 0;
INT SrcTop = 0;
INT SrcWidth = PtrWidth;
INT SrcHeight = PtrHeight;
if (PtrLeft < 0)
{
// crop mouseshape left
SrcLeft = -PtrLeft;
// new mouse x position for drawing
PtrLeft = 0;
}
else if (PtrLeft + PtrWidth > SurfWidth)
{
// crop mouseshape width
SrcWidth = SurfWidth - PtrLeft;
}
if (PtrTop < 0)
{
// crop mouseshape top
SrcTop = -PtrTop;
// new mouse y position for drawing
PtrTop = 0;
}
else if (PtrTop + PtrHeight > SurfHeight)
{
// crop mouseshape height
SrcHeight = SurfHeight - PtrTop;
}
// QI for IDXGISurface
CComPtr<IDXGISurface> ipCopySurface;
hr = pSharedSurf->QueryInterface(__uuidof(IDXGISurface), (void **)&ipCopySurface);
if (SUCCEEDED(hr)) {
// Map pixels
DXGI_MAPPED_RECT MappedSurface;
hr = ipCopySurface->Map(&MappedSurface, DXGI_MAP_READ | DXGI_MAP_WRITE);
if (SUCCEEDED(hr))
{
// 0xAARRGGBB
UINT* SrcBuffer32 = reinterpret_cast<UINT*>(InitBuffer);
UINT* DstBuffer32 = reinterpret_cast<UINT*>(MappedSurface.pBits) + PtrTop * SurfWidth + PtrLeft;
// Alpha blending masks
const UINT AMask = 0xFF000000;
const UINT RBMask = 0x00FF00FF;
const UINT GMask = 0x0000FF00;
const UINT AGMask = AMask | GMask;
const UINT OneAlpha = 0x01000000;
UINT uiPixel1;
UINT uiPixel2;
UINT uiAlpha;
UINT uiNAlpha;
UINT uiRedBlue;
UINT uiAlphaGreen;
for (INT Row = SrcTop; Row < SrcHeight; ++Row)
{
for (INT Col = SrcLeft; Col < SrcWidth; ++Col)
{
// Alpha blending
uiPixel1 = DstBuffer32[((Row - SrcTop) * SurfWidth) + (Col - SrcLeft)];
uiPixel2 = SrcBuffer32[(Row * PtrWidth) + Col];
uiAlpha = (uiPixel2 & AMask) >> 24;
uiNAlpha = 255 - uiAlpha;
uiRedBlue = ((uiNAlpha * (uiPixel1 & RBMask)) + (uiAlpha * (uiPixel2 & RBMask))) >> 8;
uiAlphaGreen = (uiNAlpha * ((uiPixel1 & AGMask) >> 8)) + (uiAlpha * (OneAlpha | ((uiPixel2 & GMask) >> 8)));
DstBuffer32[((Row - SrcTop) * SurfWidth) + (Col - SrcLeft)] = ((uiRedBlue & RBMask) | (uiAlphaGreen & AGMask));
}
}
}
// Done with resource
hr = ipCopySurface->Unmap();
}
return S_OK;
} // DrawMouse
static
COM_DECLSPEC_NOTHROW
inline
HRESULT
CreateBitmap(
_In_ ID2D1RenderTarget *pRenderTarget,
_In_ ID3D11Texture2D *pSourceTexture,
_Outptr_ ID2D1Bitmap **ppOutBitmap
)
{
CHECK_POINTER(ppOutBitmap);
*ppOutBitmap = nullptr;
CHECK_POINTER_EX(pRenderTarget, E_INVALIDARG);
CHECK_POINTER_EX(pSourceTexture, E_INVALIDARG);
HRESULT hr = S_OK;
CComPtr<ID3D11Texture2D> ipSourceTexture(pSourceTexture);
CComPtr<IDXGISurface> ipCopySurface;
CComPtr<ID2D1Bitmap> ipD2D1SourceBitmap;
// QI for IDXGISurface
hr = ipSourceTexture->QueryInterface(__uuidof(IDXGISurface), (void **)&ipCopySurface);
CHECK_HR_RETURN(hr);
// Map pixels
DXGI_MAPPED_RECT MappedSurface;
hr = ipCopySurface->Map(&MappedSurface, DXGI_MAP_READ);
CHECK_HR_RETURN(hr);
D3D11_TEXTURE2D_DESC destImageDesc;
ipSourceTexture->GetDesc(&destImageDesc);
hr = pRenderTarget->CreateBitmap(
D2D1::SizeU(destImageDesc.Width, destImageDesc.Height),
(const void*)MappedSurface.pBits,
MappedSurface.Pitch,
D2D1::BitmapProperties(D2D1::PixelFormat(DXGI_FORMAT_B8G8R8A8_UNORM, D2D1_ALPHA_MODE_PREMULTIPLIED)),
&ipD2D1SourceBitmap);
if (FAILED(hr))
{
// Done with resource
hr = ipCopySurface->Unmap();
return hr;
}
// Done with resource
hr = ipCopySurface->Unmap();
CHECK_HR_RETURN(hr);
// set return value
*ppOutBitmap = ipD2D1SourceBitmap.Detach();
return S_OK;
} // CreateBitmap
static
inline
COM_DECLSPEC_NOTHROW
HRESULT
GetContainerFormatByFileName(
_In_ LPCWSTR lpcwFileName,
_Out_opt_ GUID *pRetVal = NULL
)
{
RESET_POINTER_EX(pRetVal, GUID_NULL);
CHECK_POINTER_EX(lpcwFileName, E_INVALIDARG);
if (lstrlenW(lpcwFileName) == 0) {
return E_INVALIDARG;
}
LPCWSTR lpcwExtension = ::PathFindExtensionW(lpcwFileName);
if (lstrlenW(lpcwExtension) == 0) {
return MK_E_INVALIDEXTENSION; // ERROR_MRM_INVALID_FILE_TYPE
}
if (lstrcmpiW(lpcwExtension, L".bmp") == 0)
{
RESET_POINTER_EX(pRetVal, GUID_ContainerFormatBmp);
}
else if ((lstrcmpiW(lpcwExtension, L".tif") == 0) ||
(lstrcmpiW(lpcwExtension, L".tiff") == 0))
{
RESET_POINTER_EX(pRetVal, GUID_ContainerFormatTiff);
}
else if (lstrcmpiW(lpcwExtension, L".png") == 0)
{
RESET_POINTER_EX(pRetVal, GUID_ContainerFormatPng);
}
else if ((lstrcmpiW(lpcwExtension, L".jpg") == 0) ||
(lstrcmpiW(lpcwExtension, L".jpeg") == 0))
{
RESET_POINTER_EX(pRetVal, GUID_ContainerFormatJpeg);
}
else
{
return ERROR_MRM_INVALID_FILE_TYPE;
}
return S_OK;
}
static
COM_DECLSPEC_NOTHROW
inline
HRESULT
SaveImageToFile(
_In_ IWICImagingFactory *pWICImagingFactory,
_In_ IWICBitmapSource *pWICBitmapSource,
_In_ LPCWSTR lpcwFileName
)
{
CHECK_POINTER_EX(pWICImagingFactory, E_INVALIDARG);
CHECK_POINTER_EX(pWICBitmapSource, E_INVALIDARG);
HRESULT hr = S_OK;
GUID guidContainerFormat;
hr = GetContainerFormatByFileName(lpcwFileName, &guidContainerFormat);
if (FAILED(hr)) {
return hr;
}
WICPixelFormatGUID format = GUID_WICPixelFormatDontCare;
CComPtr<IWICImagingFactory> ipWICImagingFactory(pWICImagingFactory);
CComPtr<IWICBitmapSource> ipWICBitmapSource(pWICBitmapSource);
CComPtr<IWICStream> ipStream;
CComPtr<IWICBitmapEncoder> ipEncoder;
CComPtr<IWICBitmapFrameEncode> ipFrameEncode;
unsigned int uiWidth = 0;
unsigned int uiHeight = 0;
hr = ipWICImagingFactory->CreateStream(&ipStream);
if (SUCCEEDED(hr)) {
hr = ipStream->InitializeFromFilename(lpcwFileName, GENERIC_WRITE);
}
if (SUCCEEDED(hr)) {
hr = ipWICImagingFactory->CreateEncoder(guidContainerFormat, NULL, &ipEncoder);
}
if (SUCCEEDED(hr))
{
hr = ipEncoder->Initialize(ipStream, WICBitmapEncoderNoCache);
}
if (SUCCEEDED(hr))
{
hr = ipEncoder->CreateNewFrame(&ipFrameEncode, NULL);
}
if (SUCCEEDED(hr))
{
hr = ipFrameEncode->Initialize(NULL);
}
if (SUCCEEDED(hr))
{
hr = ipWICBitmapSource->GetSize(&uiWidth, &uiHeight);
}
if (SUCCEEDED(hr))
{
hr = ipFrameEncode->SetSize(uiWidth, uiHeight);
}
if (SUCCEEDED(hr))
{
hr = ipFrameEncode->SetPixelFormat(&format);
}
if (SUCCEEDED(hr))
{
hr = ipFrameEncode->WriteSource(ipWICBitmapSource, NULL);
}
if (SUCCEEDED(hr))
{
hr = ipFrameEncode->Commit();
}
if (SUCCEEDED(hr))
{
hr = ipEncoder->Commit();
}
return hr;
} // SaveImageToFile
}; // end class DXGICaptureHelper
#endif // __DXGICAPTUREHELPER_H__

View File

@ -0,0 +1,150 @@
/*****************************************************************************
* DXGICaptureTypes.h
*
* Copyright (C) 2020 Gokhan Erdogdu <gokhan_erdogdu - at - yahoo - dot - com>
*
* DXGICapture is free software; you can redistribute it and/or modify it under
* the terms of the GNU Lesser General Public License as published by the Free
* Software Foundation; either version 2.1 of the License, or (at your option)
* any later version.
*
* DXGICapture 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 Lesser General Public License for more
* details.
*
******************************************************************************/
#pragma once
#ifndef __DXGICAPTURETYPES_H__
#define __DXGICAPTURETYPES_H__
#include <dxgi1_2.h>
#include <windef.h>
#include <sal.h>
#include <vector>
//
// enum tagFrameSizeMode_e
//
typedef enum tagFrameSizeMode_e : UINT
{
tagFrameSizeMode_Normal = 0x0,
tagFrameSizeMode_StretchImage = 0x1,
tagFrameSizeMode_AutoSize = 0x2,
tagFrameSizeMode_CenterImage = 0x3,
tagFrameSizeMode_Zoom = 0x4,
} tagFrameSizeMode;
//
// enum tagFrameRotationMode_e
//
typedef enum tagFrameRotationMode_e : UINT
{
tagFrameRotationMode_Auto = 0x0,
tagFrameRotationMode_Identity = 0x1,
tagFrameRotationMode_90 = 0x2,
tagFrameRotationMode_180 = 0x3,
tagFrameRotationMode_270 = 0x4,
} tagFrameRotationMode;
//
// Holds info about the pointer/cursor
// struct tagMouseInfo_s
//
typedef struct tagMouseInfo_s
{
UINT ShapeBufferSize;
_Field_size_bytes_(ShapeBufferSize) BYTE* PtrShapeBuffer;
DXGI_OUTDUPL_POINTER_SHAPE_INFO ShapeInfo;
POINT Position;
bool Visible;
UINT WhoUpdatedPositionLast;
LARGE_INTEGER LastTimeStamp;
} tagMouseInfo;
//
// struct tagFrameSize_s
//
typedef struct tagFrameSize_s
{
LONG Width;
LONG Height;
} tagFrameSize;
//
// struct tagBounds_s
//
typedef struct tagFrameBounds_s
{
LONG X;
LONG Y;
LONG Width;
LONG Height;
} tagFrameBounds;
//
// struct tagFrameBufferInfo_s
//
typedef struct tagFrameBufferInfo_s
{
UINT BufferSize;
_Field_size_bytes_(BufferSize) BYTE* Buffer;
INT BytesPerPixel;
tagFrameBounds Bounds;
INT Pitch;
} tagFrameBufferInfo;
//
// struct tagDublicatorMonitorInfo_s
//
typedef struct tagDublicatorMonitorInfo_s
{
INT Idx;
WCHAR DisplayName[64];
INT RotationDegrees;
tagFrameBounds Bounds;
} tagDublicatorMonitorInfo;
typedef std::vector<tagDublicatorMonitorInfo*> DublicatorMonitorInfoVec;
//
// struct tagScreenCaptureFilterConfig_s
//
typedef struct tagScreenCaptureFilterConfig_s
{
public:
INT MonitorIdx;
INT ShowCursor;
tagFrameRotationMode RotationMode;
tagFrameSizeMode SizeMode;
tagFrameSize OutputSize; /* Discard for tagFrameSizeMode_AutoSize */
} tagScreenCaptureFilterConfig;
//
// struct tagRendererInfo_s
//
typedef struct tagRendererInfo_s
{
INT MonitorIdx;
INT ShowCursor;
tagFrameRotationMode RotationMode;
tagFrameSizeMode SizeMode;
tagFrameSize OutputSize;
FLOAT RotationDegrees;
FLOAT ScaleX;
FLOAT ScaleY;
DXGI_FORMAT SrcFormat;
tagFrameBounds SrcBounds;
tagFrameBounds DstBounds;
} tagRendererInfo;
// macros
#define RESET_POINTER_EX(p, v) if (nullptr != (p)) { *(p) = (v); }
#define RESET_POINTER(p) RESET_POINTER_EX(p, nullptr)
#define CHECK_POINTER_EX(p, hr) if (nullptr == (p)) { return (hr); }
#define CHECK_POINTER(p) CHECK_POINTER_EX(p, E_POINTER)
#define CHECK_HR_BREAK(hr) if (FAILED(hr)) { break; }
#define CHECK_HR_RETURN(hr) { HRESULT hr_379f4648 = hr; if (FAILED(hr_379f4648)) { return hr_379f4648; } }
#endif // __DXGICAPTURETYPES_H__

View File

@ -14,7 +14,6 @@ extern "C"
}; };
#include <iostream> #include <iostream>
#else #else
//Linux...
#ifdef __cplusplus #ifdef __cplusplus
extern "C" extern "C"
{ {

View File

@ -122,9 +122,9 @@ int CaptureAudioFfmpeg::InitCapture(wstring url, uint16_t rate, uint8_t channel)
return -1; return -1;
} }
//av_dump_format(infmt_ctx, 0, fileAudioInput.c_str(), 1); //av_dump_format(infmt_ctx, 0, fileAudioInput.c_str(), 1);
//END输入文件 //END输入文件
//打开解码器 //打开解码器
static AVCodec* decodec = avcodec_find_decoder(mInfmt_ctx->streams[0]->codec->codec_id); static AVCodec* decodec = avcodec_find_decoder(mInfmt_ctx->streams[0]->codec->codec_id);
if (!decodec) { if (!decodec) {
printf("failed find decoder\n"); printf("failed find decoder\n");
@ -134,11 +134,11 @@ int CaptureAudioFfmpeg::InitCapture(wstring url, uint16_t rate, uint8_t channel)
printf("failed open decoder\n"); printf("failed open decoder\n");
return -1; return -1;
} }
//END解码器 //END解码器
//重采样初始化 //重采样初始化
initAudioFilters(); initAudioFilters();
//END重采样初始化 //END重采样初始化
//编码器 //编码器
static AVCodec* codec = NULL; static AVCodec* codec = NULL;
//codec = avcodec_find_encoder_by_name("libmp3lame"); //codec = avcodec_find_encoder_by_name("libmp3lame");
codec = avcodec_find_encoder(AV_CODEC_ID_AAC); codec = avcodec_find_encoder(AV_CODEC_ID_AAC);
@ -161,8 +161,8 @@ int CaptureAudioFfmpeg::InitCapture(wstring url, uint16_t rate, uint8_t channel)
avcodec_free_context(&codec_ctx); avcodec_free_context(&codec_ctx);
return -1; return -1;
} }
//END编码器 //END编码器
//输出文件 //输出文件
AVFormatContext* outfmt_ctx = NULL; AVFormatContext* outfmt_ctx = NULL;
if (0 > avformat_alloc_output_context2(&outfmt_ctx, NULL, NULL, "aac.aac")) { if (0 > avformat_alloc_output_context2(&outfmt_ctx, NULL, NULL, "aac.aac")) {
printf("failed alloc outputcontext\n"); printf("failed alloc outputcontext\n");
@ -188,7 +188,7 @@ int CaptureAudioFfmpeg::InitCapture(wstring url, uint16_t rate, uint8_t channel)
return -1; return -1;
} }
avformat_write_header(outfmt_ctx, NULL); avformat_write_header(outfmt_ctx, NULL);
//END输出文件 //END输出文件
#if 0 #if 0
AVFrame* Frame = av_frame_alloc(); AVFrame* Frame = av_frame_alloc();
Frame->nb_samples = codec_ctx->frame_size; Frame->nb_samples = codec_ctx->frame_size;
@ -288,7 +288,8 @@ int CaptureAudioFfmpeg::initAudioFilters()
sprintf_s(args, sizeof(args), sprintf_s(args, sizeof(args),
"time_base=%d/%d:sample_rate=%d:sample_fmt=%s:channel_layout=0x%I64x", "time_base=%d/%d:sample_rate=%d:sample_fmt=%s:channel_layout=0x%I64x",
time_base.num, time_base.den, audioDecoderContext->sample_rate, time_base.num, time_base.den, audioDecoderContext->sample_rate,
av_get_sample_fmt_name(audioDecoderContext->sample_fmt), audioDecoderContext->channel_layout); av_get_sample_fmt_name(audioDecoderContext->sample_fmt),
audioDecoderContext->channel_layout);
ret = avfilter_graph_create_filter(&mBuffersrcCtx, abuffersrc, "in", ret = avfilter_graph_create_filter(&mBuffersrcCtx, abuffersrc, "in",
args, NULL, mFilterGraph); args, NULL, mFilterGraph);

View File

@ -0,0 +1,31 @@
#include "screen_capture.h"
#include <conio.h>
#include <stdio.h>
#include <QDebug>
#include <QString>
ScreenCapture::ScreenCapture()
{
}
BOOL CALLBACK MonitorEnumProc(HMONITOR hMonitor,HDC hdcMonitor,LPRECT lprcMonitor,LPARAM dwData)
{
MONITORINFOEX mi;
mi.cbSize=sizeof(MONITORINFOEX);
GetMonitorInfo(hMonitor,&mi);
qDebug()<<QString::asprintf("Device name:%s\t",mi.szDevice);
if(mi.dwFlags==MONITORINFOF_PRIMARY) printf("Primary monitor!\n");
else printf("\n");
qDebug()<<QString::asprintf("Monitor rectangle:(%d,%d,%d,%d)\n",mi.rcMonitor.left,mi.rcMonitor.top,
mi.rcMonitor.right,mi.rcMonitor.bottom);
qDebug()<<QString::asprintf("Work rectangle:(%d,%d,%d,%d)\n",mi.rcWork.left,mi.rcWork.top,
mi.rcWork.right,mi.rcWork.bottom);
return true;
}
void ScreenCapture::EnumScreen()
{
EnumDisplayMonitors(NULL,NULL,MonitorEnumProc,NULL);
}

View File

@ -0,0 +1,14 @@
#ifndef SCREEN_CAPTURE
#define SCREEN_CAPTURE
#include <Windows.h>
class ScreenCapture
{
public:
ScreenCapture();
void EnumScreen();
};
#endif // SCREEN_CAPTURE_H

View File

@ -0,0 +1,66 @@
#include <Unknwn.h>
#include <strmif.h>
#pragma comment(lib, "strmiids.lib")
#ifndef __qedit_h__
#define __qedit_h__
///////////////////////////////////////////////////////////////////////////////////
#pragma once
///////////////////////////////////////////////////////////////////////////////////
struct __declspec(uuid("0579154a-2b53-4994-b0d0-e773148eff85"))
ISampleGrabberCB : IUnknown
{
//
// Raw methods provided by interface
//
virtual HRESULT __stdcall SampleCB(
double SampleTime,
struct IMediaSample * pSample) = 0;
virtual HRESULT __stdcall BufferCB(
double SampleTime,
unsigned char * pBuffer,
long BufferLen) = 0;
};
struct __declspec(uuid("6b652fff-11fe-4fce-92ad-0266b5d7c78f"))
ISampleGrabber : IUnknown
{
//
// Raw methods provided by interface
//
virtual HRESULT __stdcall SetOneShot(
long OneShot) = 0;
virtual HRESULT __stdcall SetMediaType(
struct _AMMediaType * pType) = 0;
virtual HRESULT __stdcall GetConnectedMediaType(
struct _AMMediaType * pType) = 0;
virtual HRESULT __stdcall SetBufferSamples(
long BufferThem) = 0;
virtual HRESULT __stdcall GetCurrentBuffer(
/*[in,out]*/ long * pBufferSize,
/*[out]*/ long * pBuffer) = 0;
virtual HRESULT __stdcall GetCurrentSample(
/*[out,retval]*/ struct IMediaSample * * ppSample) = 0;
virtual HRESULT __stdcall SetCallback(
struct ISampleGrabberCB * pCallback,
long WhichMethodToCallback) = 0;
};
static const IID IID_ISampleGrabber = { 0x6B652FFF, 0x11FE, 0x4fce,{ 0x92, 0xAD, 0x02, 0x66, 0xB5, 0xD7, 0xC7, 0x8F } };
static const IID IID_ISampleGrabberCB = { 0x0579154A, 0x2B53, 0x4994,{ 0xB0, 0xD0, 0xE7, 0x73, 0x14, 0x8E, 0xFF, 0x85 } };
static const CLSID CLSID_SampleGrabber = { 0xC1F400A0, 0x3F08, 0x11d3,{ 0x9F, 0x0B, 0x00, 0x60, 0x08, 0x03, 0x9E, 0x37 } };
static const CLSID CLSID_NullRenderer = { 0xC1F400A4, 0x3F08, 0x11d3,{ 0x9F, 0x0B, 0x00, 0x60, 0x08, 0x03, 0x9E, 0x37 } };
#endif

View File

@ -0,0 +1,161 @@
/********************************************************************************
** Form generated from reading UI file 'mainwindow.ui'
**
** Created by: Qt User Interface Compiler version 5.14.0
**
** WARNING! All changes made in this file will be lost when recompiling UI file!
********************************************************************************/
#ifndef UI_MAINWINDOW_H
#define UI_MAINWINDOW_H
#include <QtCore/QVariant>
#include <QtWidgets/QApplication>
#include <QtWidgets/QComboBox>
#include <QtWidgets/QGridLayout>
#include <QtWidgets/QHBoxLayout>
#include <QtWidgets/QLabel>
#include <QtWidgets/QLineEdit>
#include <QtWidgets/QMainWindow>
#include <QtWidgets/QPushButton>
#include <QtWidgets/QSpacerItem>
#include <QtWidgets/QVBoxLayout>
#include <QtWidgets/QWidget>
QT_BEGIN_NAMESPACE
class Ui_MainWindow
{
public:
QWidget *centralWidget;
QGridLayout *gridLayout;
QVBoxLayout *verticalLayout;
QHBoxLayout *horizontalLayout;
QPushButton *pushButton;
QComboBox *comboBox;
QPushButton *pushButton_3;
QComboBox *comboBox_2;
QLabel *label;
QLineEdit *lineEdit;
QPushButton *pushButton_2;
QSpacerItem *horizontalSpacer_2;
QSpacerItem *verticalSpacer;
void setupUi(QMainWindow *MainWindow)
{
if (MainWindow->objectName().isEmpty())
MainWindow->setObjectName(QString::fromUtf8("MainWindow"));
MainWindow->resize(1383, 1116);
QSizePolicy sizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
sizePolicy.setHorizontalStretch(0);
sizePolicy.setVerticalStretch(0);
sizePolicy.setHeightForWidth(MainWindow->sizePolicy().hasHeightForWidth());
MainWindow->setSizePolicy(sizePolicy);
MainWindow->setMinimumSize(QSize(600, 800));
centralWidget = new QWidget(MainWindow);
centralWidget->setObjectName(QString::fromUtf8("centralWidget"));
QSizePolicy sizePolicy1(QSizePolicy::Expanding, QSizePolicy::Expanding);
sizePolicy1.setHorizontalStretch(0);
sizePolicy1.setVerticalStretch(0);
sizePolicy1.setHeightForWidth(centralWidget->sizePolicy().hasHeightForWidth());
centralWidget->setSizePolicy(sizePolicy1);
gridLayout = new QGridLayout(centralWidget);
gridLayout->setSpacing(6);
gridLayout->setContentsMargins(11, 11, 11, 11);
gridLayout->setObjectName(QString::fromUtf8("gridLayout"));
verticalLayout = new QVBoxLayout();
verticalLayout->setSpacing(6);
verticalLayout->setObjectName(QString::fromUtf8("verticalLayout"));
horizontalLayout = new QHBoxLayout();
horizontalLayout->setSpacing(6);
horizontalLayout->setObjectName(QString::fromUtf8("horizontalLayout"));
horizontalLayout->setContentsMargins(2, 2, 2, 1);
pushButton = new QPushButton(centralWidget);
pushButton->setObjectName(QString::fromUtf8("pushButton"));
pushButton->setMinimumSize(QSize(100, 50));
pushButton->setSizeIncrement(QSize(0, 6));
pushButton->setBaseSize(QSize(0, 50));
horizontalLayout->addWidget(pushButton);
comboBox = new QComboBox(centralWidget);
comboBox->setObjectName(QString::fromUtf8("comboBox"));
comboBox->setMinimumSize(QSize(200, 35));
comboBox->setBaseSize(QSize(0, 50));
horizontalLayout->addWidget(comboBox);
pushButton_3 = new QPushButton(centralWidget);
pushButton_3->setObjectName(QString::fromUtf8("pushButton_3"));
pushButton_3->setMinimumSize(QSize(100, 50));
horizontalLayout->addWidget(pushButton_3);
comboBox_2 = new QComboBox(centralWidget);
comboBox_2->setObjectName(QString::fromUtf8("comboBox_2"));
comboBox_2->setMinimumSize(QSize(200, 35));
horizontalLayout->addWidget(comboBox_2);
label = new QLabel(centralWidget);
label->setObjectName(QString::fromUtf8("label"));
horizontalLayout->addWidget(label);
lineEdit = new QLineEdit(centralWidget);
lineEdit->setObjectName(QString::fromUtf8("lineEdit"));
lineEdit->setMinimumSize(QSize(300, 30));
horizontalLayout->addWidget(lineEdit);
pushButton_2 = new QPushButton(centralWidget);
pushButton_2->setObjectName(QString::fromUtf8("pushButton_2"));
pushButton_2->setMinimumSize(QSize(60, 50));
horizontalLayout->addWidget(pushButton_2);
horizontalSpacer_2 = new QSpacerItem(40, 20, QSizePolicy::Expanding, QSizePolicy::Minimum);
horizontalLayout->addItem(horizontalSpacer_2);
horizontalLayout->setStretch(0, 1);
horizontalLayout->setStretch(1, 2);
horizontalLayout->setStretch(7, 13);
verticalLayout->addLayout(horizontalLayout);
verticalSpacer = new QSpacerItem(20, 40, QSizePolicy::Minimum, QSizePolicy::Expanding);
verticalLayout->addItem(verticalSpacer);
verticalLayout->setStretch(0, 1);
verticalLayout->setStretch(1, 9);
gridLayout->addLayout(verticalLayout, 0, 0, 1, 1);
MainWindow->setCentralWidget(centralWidget);
retranslateUi(MainWindow);
QMetaObject::connectSlotsByName(MainWindow);
} // setupUi
void retranslateUi(QMainWindow *MainWindow)
{
MainWindow->setWindowTitle(QCoreApplication::translate("MainWindow", "MainWindow", nullptr));
pushButton->setText(QCoreApplication::translate("MainWindow", "\346\211\223\345\274\200\346\221\204\345\203\217\345\244\264", nullptr));
pushButton_3->setText(QCoreApplication::translate("MainWindow", "\346\211\223\345\274\200\351\272\246\345\205\213\351\243\216", nullptr));
label->setText(QCoreApplication::translate("MainWindow", "rtmp\346\216\250\346\265\201\345\234\260\345\235\200", nullptr));
lineEdit->setText(QCoreApplication::translate("MainWindow", "rtmp://127.0.0.1:1935/live/1", nullptr));
pushButton_2->setText(QCoreApplication::translate("MainWindow", "\346\216\250\346\265\201", nullptr));
} // retranslateUi
};
namespace Ui {
class MainWindow: public Ui_MainWindow {};
} // namespace Ui
QT_END_NAMESPACE
#endif // UI_MAINWINDOW_H

View File

@ -0,0 +1,63 @@
/********************************************************************************
** Form generated from reading UI file 'process.ui'
**
** Created by: Qt User Interface Compiler version 5.14.0
**
** WARNING! All changes made in this file will be lost when recompiling UI file!
********************************************************************************/
#ifndef UI_PROCESS_H
#define UI_PROCESS_H
#include <QtCore/QVariant>
#include <QtWidgets/QApplication>
#include <QtWidgets/QDialog>
#include <QtWidgets/QLabel>
#include <QtWidgets/QProgressBar>
QT_BEGIN_NAMESPACE
class Ui_Process
{
public:
QProgressBar *progressBar;
QLabel *label;
void setupUi(QDialog *Process)
{
if (Process->objectName().isEmpty())
Process->setObjectName(QString::fromUtf8("Process"));
Process->resize(324, 88);
QSizePolicy sizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
sizePolicy.setHorizontalStretch(0);
sizePolicy.setVerticalStretch(0);
sizePolicy.setHeightForWidth(Process->sizePolicy().hasHeightForWidth());
Process->setSizePolicy(sizePolicy);
progressBar = new QProgressBar(Process);
progressBar->setObjectName(QString::fromUtf8("progressBar"));
progressBar->setGeometry(QRect(30, 50, 281, 31));
progressBar->setValue(24);
label = new QLabel(Process);
label->setObjectName(QString::fromUtf8("label"));
label->setGeometry(QRect(120, 30, 121, 16));
retranslateUi(Process);
QMetaObject::connectSlotsByName(Process);
} // setupUi
void retranslateUi(QDialog *Process)
{
Process->setWindowTitle(QCoreApplication::translate("Process", "Dialog", nullptr));
label->setText(QCoreApplication::translate("Process", "\346\255\243\345\234\250\345\212\240\350\275\275\346\225\260\346\215\256", nullptr));
} // retranslateUi
};
namespace Ui {
class Process: public Ui_Process {};
} // namespace Ui
QT_END_NAMESPACE
#endif // UI_PROCESS_H

View File

@ -0,0 +1,55 @@
/********************************************************************************
** Form generated from reading UI file 'qsstoast.ui'
**
** Created by: Qt User Interface Compiler version 5.14.0
**
** WARNING! All changes made in this file will be lost when recompiling UI file!
********************************************************************************/
#ifndef UI_QSSTOAST_H
#define UI_QSSTOAST_H
#include <QtCore/QVariant>
#include <QtWidgets/QApplication>
#include <QtWidgets/QLabel>
#include <QtWidgets/QWidget>
QT_BEGIN_NAMESPACE
class Ui_Toast
{
public:
QLabel *label;
void setupUi(QWidget *Toast)
{
if (Toast->objectName().isEmpty())
Toast->setObjectName(QString::fromUtf8("Toast"));
Toast->resize(932, 59);
QFont font;
font.setFamily(QString::fromUtf8("Arial"));
Toast->setFont(font);
label = new QLabel(Toast);
label->setObjectName(QString::fromUtf8("label"));
label->setGeometry(QRect(170, 10, 231, 31));
retranslateUi(Toast);
QMetaObject::connectSlotsByName(Toast);
} // setupUi
void retranslateUi(QWidget *Toast)
{
Toast->setWindowTitle(QCoreApplication::translate("Toast", "Form", nullptr));
label->setText(QCoreApplication::translate("Toast", "TextLabel", nullptr));
} // retranslateUi
};
namespace Ui {
class Toast: public Ui_Toast {};
} // namespace Ui
QT_END_NAMESPACE
#endif // UI_QSSTOAST_H

View File

@ -0,0 +1,52 @@
/********************************************************************************
** Form generated from reading UI file 'toast.ui'
**
** Created by: Qt User Interface Compiler version 5.14.0
**
** WARNING! All changes made in this file will be lost when recompiling UI file!
********************************************************************************/
#ifndef UI_TOAST_H
#define UI_TOAST_H
#include <QtCore/QVariant>
#include <QtWidgets/QApplication>
#include <QtWidgets/QLabel>
#include <QtWidgets/QWidget>
QT_BEGIN_NAMESPACE
class Ui_Form
{
public:
QLabel *label;
void setupUi(QWidget *Form)
{
if (Form->objectName().isEmpty())
Form->setObjectName(QString::fromUtf8("Form"));
Form->resize(932, 59);
label = new QLabel(Form);
label->setObjectName(QString::fromUtf8("label"));
label->setGeometry(QRect(170, 10, 231, 31));
retranslateUi(Form);
QMetaObject::connectSlotsByName(Form);
} // setupUi
void retranslateUi(QWidget *Form)
{
Form->setWindowTitle(QCoreApplication::translate("Form", "Form", nullptr));
label->setText(QCoreApplication::translate("Form", "TextLabel", nullptr));
} // retranslateUi
};
namespace Ui {
class Form: public Ui_Form {};
} // namespace Ui
QT_END_NAMESPACE
#endif // UI_TOAST_H

View File

@ -42,39 +42,74 @@ SOURCES += \
media/AACAudioCoder.cpp \ media/AACAudioCoder.cpp \
media/AudioCapture.cpp \ media/AudioCapture.cpp \
media/CameraCapture.cpp \ media/CameraCapture.cpp \
media/DXGICapture.cpp \
media/RtmpPusher.cpp \ media/RtmpPusher.cpp \
media/VideoCoder.cpp \ media/VideoCoder.cpp \
media/audiocaptureff.cpp \ media/audiocaptureff.cpp \
media/screen_capture.cpp \
media/sps_decode.cpp \ media/sps_decode.cpp \
utils/Base64.cpp \ utils/Base64.cpp \
utils/Debuger.cpp \ utils/Debuger.cpp \
utils/utils.cpp utils/utils.cpp
HEADERS += \ HEADERS += \
components/toast.h \ components/toast.h \
librtmp/strncasecmp.h \
mainwindow.h \ mainwindow.h \
cplaywidget.h \ cplaywidget.h \
cplaywidget.h \ media/screen_capture.h
media/audiocaptureff.h
FORMS += \ FORMS += \
components/toast.ui \ components/toast.ui \
mainwindow.ui mainwindow.ui
INCLUDEPATH += media/ third/ffmpeg/include/ inc/ third/
INCLUDEPATH += media/
contains(DEFINES, __MINGW32__){ contains(DEFINES, __MINGW32__){
message("sfasdfdsf") message("mingw")
LIBS += -L$$PWD/third/libs/ INCLUDEPATH += media/ inc/
contains(QT_ARCH, i386) {
message("32-bit")
LIBS += -L$$PWD/third/ffmpeg/mingw/32/lib
LIBS += -lm -lavformat -lavdevice -lavfilter -lavcodec -lavutil -lswresample -lswscale -lpthread -lm -lfdk-aac -lx264 -liconv -lucrtbase -lstrmiids LIBS += -lm -lavformat -lavdevice -lavfilter -lavcodec -lavutil -lswresample -lswscale -lpthread -lm -lfdk-aac -lx264 -liconv -lucrtbase -lstrmiids
LIBS += -lole32 -loleAut32 -lquartz -ldxguid -ldxapi -lwinmm -lbcrypt -lssl -lcrypto -lGdi32 -lws2_32 -lbz2 -lz -lportaudio -lshlwapi -lvfw32 -lpostproc -luuid LIBS += -lole32 -loleAut32 -lquartz -ldxguid -ldxapi -lwinmm -lbcrypt -lssl -lcrypto -lGdi32 -lws2_32 -lbz2 -lz -lportaudio -lshlwapi -lvfw32 -lpostproc -luuid
} else { } else {
message("111") message("64-bit")
LIBS += -L$$PWD/third/libs/
LIBS += -lm -lavformat -lavdevice -lavfilter -lavcodec -lavutil -lswresample -lswscale -lpthread -lm -lfdk-aac -lx264 -liconv -lucrtbase -lstrmiids
LIBS += -lole32 -loleAut32 -lquartz -ldxguid -ldxapi -lwinmm -lbcrypt -lssl -lcrypto -lGdi32 -lz -lportaudio -lshlwapi -lvfw32 -lpostproc -luuid
} }
}else{
message("msvc")
DEFINES += _CRT_SECURE_NO_DEPRECATE \
_CRT_NONSTDC_NO_DEPRECATE
contains(QT_ARCH, i386) {
INCLUDEPATH += inc $$PWD/third/msvc32/fdk-aac/include \
$$PWD/third/msvc32/libx264/include \
$$PWD/third/msvc32/ffmpeg/include \
$$PWD/third/msvc32/openssl/include
LIBS += -L$$PWD/third/msvc32/libx264/lib
LIBS += -L$$PWD/third/msvc32/fdk-aac/lib
LIBS += -L$$PWD/third/msvc32/ffmpeg/lib
LIBS += -L$$PWD/third/msvc32/openssl/lib
LIBS += libavfilter.a libavdevice.a libavcodec.a libpostproc.a \
libavformat.a libavutil.a \
libswresample.a libswscale.a fdk-aac.lib ws2_32.lib libeay32.lib ssleay32.lib \
shell32.lib gdi32.lib crypt32.lib User32.lib GDI32.lib Advapi32.lib zlibstaticd.lib Secur32.lib \
Bcrypt.lib Kernel32.lib portaudio_x86.lib ole32.lib oleaut32.lib strmiids.lib libx264.lib
}
else{
message("64-bit")
QMAKE_CXXFLAGS_RELEASE += -Zi QMAKE_CXXFLAGS_RELEASE += -Zi
QMAKE_LFLAGS_RELEASE += /DEBUG /OPT:REF QMAKE_LFLAGS_RELEASE += /DEBUG /OPT:REF
}
}
qnx: target.path = /tmp/$${TARGET}/bin qnx: target.path = /tmp/$${TARGET}/bin
else: unix:!android: target.path = /opt/$${TARGET}/bin else: unix:!android: target.path = /opt/$${TARGET}/bin

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE QtCreatorProject> <!DOCTYPE QtCreatorProject>
<!-- Written by QtCreator 4.11.0, 2021-10-02T02:21:21. --> <!-- Written by QtCreator 4.11.0, 2021-10-04T20:14:49. -->
<qtcreator> <qtcreator>
<data> <data>
<variable>EnvironmentId</variable> <variable>EnvironmentId</variable>
@ -71,7 +71,7 @@
<value type="int" key="ProjectExplorer.Target.ActiveDeployConfiguration">0</value> <value type="int" key="ProjectExplorer.Target.ActiveDeployConfiguration">0</value>
<value type="int" key="ProjectExplorer.Target.ActiveRunConfiguration">0</value> <value type="int" key="ProjectExplorer.Target.ActiveRunConfiguration">0</value>
<valuemap type="QVariantMap" key="ProjectExplorer.Target.BuildConfiguration.0"> <valuemap type="QVariantMap" key="ProjectExplorer.Target.BuildConfiguration.0">
<value type="QString" key="ProjectExplorer.BuildConfiguration.BuildDirectory">D:/project/multimedia/client/qt_gl_/yuvgl</value> <value type="QString" key="ProjectExplorer.BuildConfiguration.BuildDirectory">D:/project/multimedia/client/qt_gl_/build-yuvgl-Desktop_Qt_5_14_0_MSVC2017_32bit-Debug</value>
<valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0"> <valuemap type="QVariantMap" key="ProjectExplorer.BuildConfiguration.BuildStepList.0">
<valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0"> <valuemap type="QVariantMap" key="ProjectExplorer.BuildStepList.Step.0">
<value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value> <value type="bool" key="ProjectExplorer.BuildStep.Enabled">true</value>
@ -299,7 +299,7 @@
<value type="bool" key="RunConfiguration.UseQmlDebugger">false</value> <value type="bool" key="RunConfiguration.UseQmlDebugger">false</value>
<value type="bool" key="RunConfiguration.UseQmlDebuggerAuto">true</value> <value type="bool" key="RunConfiguration.UseQmlDebuggerAuto">true</value>
<value type="QString" key="RunConfiguration.WorkingDirectory"></value> <value type="QString" key="RunConfiguration.WorkingDirectory"></value>
<value type="QString" key="RunConfiguration.WorkingDirectory.default">D:/project/multimedia/client/qt_gl_/yuvgl</value> <value type="QString" key="RunConfiguration.WorkingDirectory.default">D:/project/multimedia/client/qt_gl_/build-yuvgl-Desktop_Qt_5_14_0_MSVC2017_32bit-Debug</value>
</valuemap> </valuemap>
<value type="int" key="ProjectExplorer.Target.RunConfigurationCount">1</value> <value type="int" key="ProjectExplorer.Target.RunConfigurationCount">1</value>
</valuemap> </valuemap>

1916
client/qt_gl_/yuvgl/zlib.h Normal file

File diff suppressed because it is too large Load Diff