Skip to content

Commit 4537f48

Browse files
mamoreau-devolutionsawakecoding
authored andcommitted
session recording improvements
1 parent 0756bde commit 4537f48

15 files changed

Lines changed: 500 additions & 64 deletions

dll/ApiHooks.cpp

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -404,9 +404,11 @@ bool WINAPI MsRdpEx_CaptureBlt(
404404
bool captured = false;
405405
bool outputMirrorEnabled = false;
406406
bool videoRecordingEnabled = false;
407+
uint32_t videoRecordingQuality = 5;
407408
bool dumpBitmapUpdates = false;
408409
IMsRdpExInstance* instance = NULL;
409410
MsRdpEx_OutputMirror* outputMirror = NULL;
411+
CMsRdpExtendedSettings* pExtendedSettings = NULL;
410412

411413
HWND hWnd = WindowFromDC(hdcDst);
412414

@@ -418,11 +420,18 @@ bool WINAPI MsRdpEx_CaptureBlt(
418420
if (!instance)
419421
goto end;
420422

423+
if (instance)
424+
instance->GetExtendedSettings(&pExtendedSettings);
425+
426+
if (!pExtendedSettings)
427+
goto end;
428+
421429
MsRdpEx_LogPrint(TRACE, "CaptureBlt: hWnd: %p instance: %p", hWnd, instance);
422430

423-
instance->GetOutputMirrorEnabled(&outputMirrorEnabled);
424-
instance->GetVideoRecordingEnabled(&videoRecordingEnabled);
425-
instance->GetDumpBitmapUpdates(&dumpBitmapUpdates);
431+
outputMirrorEnabled = pExtendedSettings->GetOutputMirrorEnabled();
432+
videoRecordingEnabled = pExtendedSettings->GetVideoRecordingEnabled();
433+
videoRecordingQuality = pExtendedSettings->GetVideoRecordingQuality();
434+
dumpBitmapUpdates = pExtendedSettings->GetDumpBitmapUpdates();
426435

427436
if (!outputMirrorEnabled)
428437
goto end;
@@ -440,6 +449,17 @@ bool WINAPI MsRdpEx_CaptureBlt(
440449
outputMirror = MsRdpEx_OutputMirror_New();
441450
MsRdpEx_OutputMirror_SetDumpBitmapUpdates(outputMirror, dumpBitmapUpdates);
442451
MsRdpEx_OutputMirror_SetVideoRecordingEnabled(outputMirror, videoRecordingEnabled);
452+
MsRdpEx_OutputMirror_SetVideoQualityLevel(outputMirror, videoRecordingQuality);
453+
454+
char* recordingPath = pExtendedSettings->GetRecordingPath();
455+
if (recordingPath) {
456+
MsRdpEx_OutputMirror_SetRecordingPath(outputMirror, recordingPath);
457+
free(recordingPath);
458+
}
459+
460+
const char* sessionId = pExtendedSettings->GetSessionId();
461+
MsRdpEx_OutputMirror_SetSessionId(outputMirror, sessionId);
462+
443463
instance->SetOutputMirrorObject((LPVOID) outputMirror);
444464
}
445465

dll/AxHost/RdpComBase.h

Lines changed: 4 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,9 @@
1-
#ifndef MSRDPEX_COM_HELPER_H
2-
#define MSRDPEX_COM_HELPER_H
1+
#ifndef MSRDPEX_COM_BASE_H
2+
#define MSRDPEX_COM_BASE_H
33

4-
#include <MsRdpEx/MsRdpEx.h>
5-
6-
#include <atlbase.h>
7-
#include <oleidl.h>
8-
#include <commctrl.h>
9-
10-
#ifndef SafeRelease
11-
#define SafeRelease(_x) { if ((_x) != nullptr) { (_x)->Release(); (_x) = nullptr; } }
12-
#endif
13-
14-
#ifndef ToVariantBool
15-
#define ToVariantBool(_b) ((_b) ? VARIANT_TRUE : VARIANT_FALSE)
16-
#endif
4+
#include "../ComHelpers.h"
175

186
#include "../com/mstscax.tlh"
197
using namespace MSTSCLib;
208

21-
#endif /* MSRDPEX_COM_HELPER_H */
9+
#endif /* MSRDPEX_COM_BASE_H */

dll/ComHelpers.h

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
#ifndef MSRDPEX_COM_HELPERS_H
2+
#define MSRDPEX_COM_HELPERS_H
3+
4+
#include <MsRdpEx/MsRdpEx.h>
5+
6+
#include <atlbase.h>
7+
#include <oleidl.h>
8+
#include <commctrl.h>
9+
10+
#ifndef SafeRelease
11+
#define SafeRelease(_x) { if ((_x) != nullptr) { (_x)->Release(); (_x) = nullptr; } }
12+
#endif
13+
14+
#ifndef ToVariantBool
15+
#define ToVariantBool(_b) ((_b) ? VARIANT_TRUE : VARIANT_FALSE)
16+
#endif
17+
18+
#define VariantInitBool(pv, b) \
19+
do { \
20+
VariantInit((pv)); \
21+
(pv)->vt = VT_BOOL; \
22+
(pv)->boolVal = ((b) ? VARIANT_TRUE : VARIANT_FALSE); \
23+
} while (0)
24+
25+
#endif /* MSRDPEX_COM_HELPERS_H */

dll/File.c

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,33 @@ const char* MsRdpEx_FileBase(const char* filename)
3333
return filename;
3434
}
3535

36+
char* MsRdpEx_FileDir(const char* filename)
37+
{
38+
size_t length;
39+
char* separator;
40+
41+
if (!filename)
42+
return NULL;
43+
44+
separator = strrchr(filename, '\\');
45+
46+
if (!separator)
47+
separator = strrchr(filename, '/');
48+
49+
if (!separator)
50+
return NULL;
51+
52+
length = (separator - filename) + 1; // include the separator
53+
char* dirname = (char*)malloc(length + 1);
54+
if (!dirname)
55+
return NULL;
56+
57+
memcpy(dirname, filename, length);
58+
dirname[length] = '\0';
59+
60+
return dirname;
61+
}
62+
3663
bool MsRdpEx_FileExists(const char* filename)
3764
{
3865
bool result = false;
@@ -241,6 +268,32 @@ bool MsRdpEx_MakePath(const char* path, LPSECURITY_ATTRIBUTES lpAttributes)
241268
return result;
242269
}
243270

271+
BOOL MsRdpEx_MoveFile(LPCSTR lpExistingFileName, LPCSTR lpNewFileName, DWORD flags)
272+
{
273+
BOOL result = FALSE;
274+
LPWSTR lpExistingFileNameW = NULL;
275+
LPWSTR lpNewFileNameW = NULL;
276+
277+
if (!lpExistingFileName)
278+
goto cleanup;
279+
280+
if (MsRdpEx_ConvertToUnicode(CP_UTF8, 0, lpExistingFileName, -1, &lpExistingFileNameW, 0) < 1)
281+
goto cleanup;
282+
283+
if (lpNewFileName)
284+
{
285+
if (MsRdpEx_ConvertToUnicode(CP_UTF8, 0, lpNewFileName, -1, &lpNewFileNameW, 0) < 1)
286+
goto cleanup;
287+
}
288+
289+
result = MoveFileExW(lpExistingFileNameW, lpNewFileNameW, flags);
290+
291+
cleanup:
292+
free(lpExistingFileNameW);
293+
free(lpNewFileNameW);
294+
return result;
295+
}
296+
244297
uint64_t MsRdpEx_GetUnixTime()
245298
{
246299
uint64_t unixTime;

dll/MsRdpClient.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -205,7 +205,10 @@ class CMsRdpClient : public IMsRdpClient10
205205
}
206206

207207
if (m_pMsRdpExInstance) {
208+
IMsRdpExInstance* pMsRdpExInstance = (IMsRdpExInstance*)m_pMsRdpExInstance;
208209
MsRdpEx_InstanceManager_Remove(m_pMsRdpExInstance);
210+
pMsRdpExInstance->Release();
211+
pMsRdpExInstance = NULL;
209212
}
210213
}
211214

@@ -499,6 +502,7 @@ class CMsRdpClient : public IMsRdpClient10
499502
m_pMsRdpExtendedSettings->LoadRdpFileFromNamedPipe(NULL);
500503
m_pMsRdpExtendedSettings->PrepareSspiSessionIdHack();
501504
m_pMsRdpExtendedSettings->PrepareMouseJiggler();
505+
m_pMsRdpExtendedSettings->PrepareVideoRecorder();
502506
m_pMsRdpExtendedSettings->PrepareExtraSystemMenu();
503507

504508
hr = m_pMsTscAx->raw_Connect();

dll/OutputMirror.c

Lines changed: 42 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,13 @@ struct _MsRdpEx_OutputMirror
2020
HGDIOBJ hShadowObject;
2121
uint32_t captureIndex;
2222
uint64_t captureBaseTime;
23-
char capturePath[MSRDPEX_MAX_PATH];
2423

24+
int videoRecordingCount;
2525
bool dumpBitmapUpdates;
2626
bool videoRecordingEnabled;
27+
uint32_t videoQualityLevel;
28+
char recordingPath[MSRDPEX_MAX_PATH];
29+
char sessionId[MSRDPEX_GUID_STRING_SIZE];
2730
MsRdpEx_VideoRecorder* videoRecorder;
2831
FILE* frameMetadataFile;
2932

@@ -84,7 +87,7 @@ bool MsRdpEx_OutputMirror_DumpFrame(MsRdpEx_OutputMirror* ctx)
8487
if (ctx->dumpBitmapUpdates) {
8588
char metadata[1024];
8689

87-
sprintf_s(filename, MSRDPEX_MAX_PATH, "%s\\frame_%04d.bmp", ctx->capturePath, ctx->captureIndex);
90+
sprintf_s(filename, MSRDPEX_MAX_PATH, "%s\\%s\\frame_%04d.bmp", ctx->recordingPath, ctx->sessionId, ctx->captureIndex);
8891
MsRdpEx_WriteBitmapFile(filename, ctx->bitmapData, ctx->bitmapWidth, ctx->bitmapHeight, ctx->bitsPerPixel);
8992

9093
sprintf_s(metadata, sizeof(metadata), "%llu|%dx%d|%s|%dx%d|%dx%d\n",
@@ -109,6 +112,21 @@ void MsRdpEx_OutputMirror_SetVideoRecordingEnabled(MsRdpEx_OutputMirror* ctx, bo
109112
ctx->videoRecordingEnabled = videoRecordingEnabled;
110113
}
111114

115+
void MsRdpEx_OutputMirror_SetVideoQualityLevel(MsRdpEx_OutputMirror* ctx, uint32_t videoQualityLevel)
116+
{
117+
ctx->videoQualityLevel = videoQualityLevel;
118+
}
119+
120+
void MsRdpEx_OutputMirror_SetRecordingPath(MsRdpEx_OutputMirror* ctx, const char* recordingPath)
121+
{
122+
strcpy_s(ctx->recordingPath, MSRDPEX_MAX_PATH, recordingPath);
123+
}
124+
125+
void MsRdpEx_OutputMirror_SetSessionId(MsRdpEx_OutputMirror* ctx, const char* sessionId)
126+
{
127+
strcpy_s(ctx->sessionId, MSRDPEX_GUID_STRING_SIZE, sessionId);
128+
}
129+
112130
bool MsRdpEx_OutputMirror_GetShadowBitmap(MsRdpEx_OutputMirror* ctx,
113131
HDC* phDC, HBITMAP* phBitmap, uint8_t** pBitmapData,
114132
uint32_t* pBitmapWidth, uint32_t* pBitmapHeight, uint32_t* pBitmapStep)
@@ -143,43 +161,45 @@ bool MsRdpEx_OutputMirror_Init(MsRdpEx_OutputMirror* ctx)
143161

144162
ctx->captureBaseTime = GetTickCount64();
145163

146-
char* capturePath = MsRdpEx_GetEnv("MSRDPEX_CAPTURE_PATH");
164+
char* envRecordingPath = MsRdpEx_GetEnv("MSRDPEX_RECORDING_PATH");
165+
if (envRecordingPath) {
166+
MsRdpEx_OutputMirror_SetRecordingPath(ctx, envRecordingPath);
167+
free(envRecordingPath);
168+
}
147169

148-
if (capturePath) {
149-
strcpy_s(ctx->capturePath, MSRDPEX_MAX_PATH, capturePath);
150-
free(capturePath);
151-
} else {
170+
if (MsRdpEx_StringIsNullOrEmpty(ctx->recordingPath)) {
152171
const char* appDataPath = MsRdpEx_GetPath(MSRDPEX_APP_DATA_PATH);
153-
sprintf_s(ctx->capturePath, MSRDPEX_MAX_PATH, "%s\\capture", appDataPath);
172+
sprintf_s(ctx->recordingPath, MSRDPEX_MAX_PATH, "%s\\recordings", appDataPath);
173+
}
174+
175+
if (MsRdpEx_StringIsNullOrEmpty(ctx->sessionId)) {
176+
GUID guid;
177+
MsRdpEx_GuidGenerate(&guid);
178+
MsRdpEx_GuidBinToStr((GUID*)&guid, ctx->sessionId, 0);
154179
}
155180

156181
if (ctx->videoRecordingEnabled) {
182+
char outputPath[MSRDPEX_MAX_PATH];
157183
char filename[MSRDPEX_MAX_PATH];
158-
uint64_t timestamp = MsRdpEx_GetUnixTime();
159184

160-
MsRdpEx_MakePath(ctx->capturePath, NULL);
185+
sprintf_s(outputPath, MSRDPEX_MAX_PATH, "%s\\%s", ctx->recordingPath, ctx->sessionId);
186+
MsRdpEx_MakePath(outputPath, NULL);
161187

162188
ctx->videoRecorder = MsRdpEx_VideoRecorder_New();
163189

164190
if (ctx->videoRecorder) {
165-
char* videoFileName = MsRdpEx_GetEnv("MSRDPEX_VIDEO_FILENAME");
166-
167-
if (videoFileName) {
168-
strcpy_s(filename, MSRDPEX_MAX_PATH, videoFileName);
169-
free(videoFileName);
170-
} else {
171-
sprintf_s(filename, MSRDPEX_MAX_PATH, "%s\\%llu.webm", ctx->capturePath, timestamp);
172-
}
173-
191+
sprintf_s(filename, MSRDPEX_MAX_PATH, "%s\\recording-%d.webm", outputPath, ctx->videoRecordingCount);
192+
ctx->videoRecordingCount++;
174193
MsRdpEx_VideoRecorder_SetFrameSize(ctx->videoRecorder, ctx->bitmapWidth, ctx->bitmapHeight);
175194
MsRdpEx_VideoRecorder_SetFileName(ctx->videoRecorder, filename);
195+
MsRdpEx_VideoRecorder_SetVideoQuality(ctx->videoRecorder, ctx->videoQualityLevel);
176196
MsRdpEx_VideoRecorder_Init(ctx->videoRecorder);
177197
}
178198

179199
if (ctx->dumpBitmapUpdates) {
180200
char metadata[1024];
181201
sprintf_s(metadata, sizeof(metadata), "FrameTime|FrameSize|FrameFile|UpdatePos|UpdateSize\n");
182-
sprintf_s(filename, MSRDPEX_MAX_PATH, "%s\\frame_meta.psv", ctx->capturePath);
202+
sprintf_s(filename, MSRDPEX_MAX_PATH, "%s\\frame_meta.psv", outputPath);
183203
ctx->frameMetadataFile = MsRdpEx_FileOpen(filename, "wb");
184204
fwrite(metadata, 1, strlen(metadata), ctx->frameMetadataFile);
185205
}
@@ -206,6 +226,7 @@ bool MsRdpEx_OutputMirror_Uninit(MsRdpEx_OutputMirror* ctx)
206226

207227
if (ctx->videoRecorder) {
208228
MsRdpEx_VideoRecorder_Uninit(ctx->videoRecorder);
229+
MsRdpEx_VideoRecorder_Remux(ctx->videoRecorder, NULL);
209230
MsRdpEx_VideoRecorder_Free(ctx->videoRecorder);
210231
ctx->videoRecorder = NULL;
211232
}
@@ -229,6 +250,7 @@ MsRdpEx_OutputMirror* MsRdpEx_OutputMirror_New()
229250

230251
ctx->bitsPerPixel = 32;
231252
ctx->videoRecordingEnabled = false;
253+
ctx->videoQualityLevel = 5;
232254
ctx->dumpBitmapUpdates = false;
233255

234256
InitializeCriticalSectionAndSpinCount(&ctx->lock, 4000);

0 commit comments

Comments
 (0)