@@ -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+
112130bool 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