FreeRDP
Loading...
Searching...
No Matches
shadow_encoder.c
1
19#include <freerdp/config.h>
20
21#include <winpr/assert.h>
22
23#include "shadow.h"
24
25#include "shadow_encoder.h"
26
27#include <freerdp/log.h>
28#define TAG CLIENT_TAG("shadow")
29
30UINT32 shadow_encoder_preferred_fps(rdpShadowEncoder* encoder)
31{
32 /* Return preferred fps calculated according to the last
33 * sent frame id and last client-acknowledged frame id.
34 */
35 return encoder->fps;
36}
37
38UINT32 shadow_encoder_inflight_frames(rdpShadowEncoder* encoder)
39{
40 /* Return in-flight frame count.
41 * If queueDepth is SUSPEND_FRAME_ACKNOWLEDGEMENT, count = 0
42 * Otherwise, calculate count =
43 * <last sent frame id> - <last client-acknowledged frame id>
44 * Note: This function is exported so that subsystem could
45 * implement its own strategy to tune fps.
46 */
47 return (encoder->queueDepth == SUSPEND_FRAME_ACKNOWLEDGEMENT)
48 ? 0
49 : encoder->frameId - encoder->lastAckframeId;
50}
51
52UINT32 shadow_encoder_create_frame_id(rdpShadowEncoder* encoder)
53{
54 UINT32 frameId = 0;
55 UINT32 inFlightFrames = shadow_encoder_inflight_frames(encoder);
56
57 /*
58 * Calculate preferred fps according to how much frames are
59 * in-progress. Note that it only works when subsystem implementation
60 * calls shadow_encoder_preferred_fps and takes the suggestion.
61 */
62 if (inFlightFrames > 1)
63 {
64 encoder->fps = (100 / (inFlightFrames + 1) * encoder->maxFps) / 100;
65 }
66 else
67 {
68 encoder->fps += 2;
69
70 if (encoder->fps > encoder->maxFps)
71 encoder->fps = encoder->maxFps;
72 }
73
74 if (encoder->fps < 1)
75 encoder->fps = 1;
76
77 frameId = ++encoder->frameId;
78 return frameId;
79}
80
81static int shadow_encoder_init_grid(rdpShadowEncoder* encoder)
82{
83 UINT32 tileSize = 0;
84 UINT32 tileCount = 0;
85 encoder->gridWidth = ((encoder->width + (encoder->maxTileWidth - 1)) / encoder->maxTileWidth);
86 encoder->gridHeight =
87 ((encoder->height + (encoder->maxTileHeight - 1)) / encoder->maxTileHeight);
88 tileSize = encoder->maxTileWidth * encoder->maxTileHeight * 4;
89 tileCount = encoder->gridWidth * encoder->gridHeight;
90 encoder->gridBuffer = (BYTE*)calloc(tileSize, tileCount);
91
92 if (!encoder->gridBuffer)
93 return -1;
94
95 encoder->grid = (BYTE**)calloc(tileCount, sizeof(BYTE*));
96
97 if (!encoder->grid)
98 return -1;
99
100 for (UINT32 i = 0; i < encoder->gridHeight; i++)
101 {
102 for (UINT32 j = 0; j < encoder->gridWidth; j++)
103 {
104 const size_t k = (1ULL * i * encoder->gridWidth) + j;
105 encoder->grid[k] = &(encoder->gridBuffer[k * tileSize]);
106 }
107 }
108
109 return 0;
110}
111
112static int shadow_encoder_uninit_grid(rdpShadowEncoder* encoder)
113{
114 if (encoder->gridBuffer)
115 {
116 free(encoder->gridBuffer);
117 encoder->gridBuffer = NULL;
118 }
119
120 if (encoder->grid)
121 {
122 free((void*)encoder->grid);
123 encoder->grid = NULL;
124 }
125
126 encoder->gridWidth = 0;
127 encoder->gridHeight = 0;
128 return 0;
129}
130
131static int shadow_encoder_init_rfx(rdpShadowEncoder* encoder)
132{
133 if (!encoder->rfx)
134 encoder->rfx = rfx_context_new_ex(
135 TRUE, freerdp_settings_get_uint32(encoder->server->settings, FreeRDP_ThreadingFlags));
136
137 if (!encoder->rfx)
138 goto fail;
139
140 if (!rfx_context_reset(encoder->rfx, encoder->width, encoder->height))
141 goto fail;
142
143 {
144 const UINT32 mode =
145 freerdp_settings_get_uint32(encoder->server->settings, FreeRDP_RemoteFxRlgrMode);
146 rfx_context_set_mode(encoder->rfx, WINPR_ASSERTING_INT_CAST(RLGR_MODE, mode));
147 }
148 rfx_context_set_pixel_format(encoder->rfx, PIXEL_FORMAT_BGRX32);
149 encoder->codecs |= FREERDP_CODEC_REMOTEFX;
150 return 1;
151fail:
152 rfx_context_free(encoder->rfx);
153 return -1;
154}
155
156static int shadow_encoder_init_nsc(rdpShadowEncoder* encoder)
157{
158 rdpContext* context = (rdpContext*)encoder->client;
159 rdpSettings* settings = context->settings;
160
161 if (!encoder->nsc)
162 encoder->nsc = nsc_context_new();
163
164 if (!encoder->nsc)
165 goto fail;
166
167 if (!nsc_context_reset(encoder->nsc, encoder->width, encoder->height))
168 goto fail;
169
170 if (!nsc_context_set_parameters(
171 encoder->nsc, NSC_COLOR_LOSS_LEVEL,
172 freerdp_settings_get_uint32(settings, FreeRDP_NSCodecColorLossLevel)))
173 goto fail;
174 if (!nsc_context_set_parameters(
175 encoder->nsc, NSC_ALLOW_SUBSAMPLING,
176 freerdp_settings_get_bool(settings, FreeRDP_NSCodecAllowSubsampling) ? 1 : 0))
177 goto fail;
178 if (!nsc_context_set_parameters(
179 encoder->nsc, NSC_DYNAMIC_COLOR_FIDELITY,
180 !freerdp_settings_get_bool(settings, FreeRDP_NSCodecAllowDynamicColorFidelity)))
181 goto fail;
182 if (!nsc_context_set_parameters(encoder->nsc, NSC_COLOR_FORMAT, PIXEL_FORMAT_BGRX32))
183 goto fail;
184 encoder->codecs |= FREERDP_CODEC_NSCODEC;
185 return 1;
186fail:
187 nsc_context_free(encoder->nsc);
188 return -1;
189}
190
191static int shadow_encoder_init_planar(rdpShadowEncoder* encoder)
192{
193 DWORD planarFlags = 0;
194 rdpContext* context = (rdpContext*)encoder->client;
195 rdpSettings* settings = context->settings;
196
197 if (freerdp_settings_get_bool(settings, FreeRDP_DrawAllowSkipAlpha))
198 planarFlags |= PLANAR_FORMAT_HEADER_NA;
199
200 planarFlags |= PLANAR_FORMAT_HEADER_RLE;
201
202 if (!encoder->planar)
203 {
204 encoder->planar = freerdp_bitmap_planar_context_new(planarFlags, encoder->maxTileWidth,
205 encoder->maxTileHeight);
206 }
207
208 if (!encoder->planar)
209 goto fail;
210
211 if (!freerdp_bitmap_planar_context_reset(encoder->planar, encoder->maxTileWidth,
212 encoder->maxTileHeight))
213 goto fail;
214
215 encoder->codecs |= FREERDP_CODEC_PLANAR;
216 return 1;
217fail:
218 freerdp_bitmap_planar_context_free(encoder->planar);
219 return -1;
220}
221
222static int shadow_encoder_init_interleaved(rdpShadowEncoder* encoder)
223{
224 if (!encoder->interleaved)
225 encoder->interleaved = bitmap_interleaved_context_new(TRUE);
226
227 if (!encoder->interleaved)
228 goto fail;
229
230 if (!bitmap_interleaved_context_reset(encoder->interleaved))
231 goto fail;
232
233 encoder->codecs |= FREERDP_CODEC_INTERLEAVED;
234 return 1;
235fail:
236 bitmap_interleaved_context_free(encoder->interleaved);
237 return -1;
238}
239
240static int shadow_encoder_init_h264(rdpShadowEncoder* encoder)
241{
242 if (!encoder->h264)
243 encoder->h264 = h264_context_new(TRUE);
244
245 if (!encoder->h264)
246 goto fail;
247
248 if (!h264_context_reset(encoder->h264, encoder->width, encoder->height))
249 goto fail;
250
251 if (!h264_context_set_option(encoder->h264, H264_CONTEXT_OPTION_RATECONTROL,
252 encoder->server->h264RateControlMode))
253 goto fail;
254 if (!h264_context_set_option(encoder->h264, H264_CONTEXT_OPTION_BITRATE,
255 encoder->server->h264BitRate))
256 goto fail;
257 if (!h264_context_set_option(encoder->h264, H264_CONTEXT_OPTION_FRAMERATE,
258 encoder->server->h264FrameRate))
259 goto fail;
260 if (!h264_context_set_option(encoder->h264, H264_CONTEXT_OPTION_QP, encoder->server->h264QP))
261 goto fail;
262
263 encoder->codecs |= FREERDP_CODEC_AVC420 | FREERDP_CODEC_AVC444;
264 return 1;
265fail:
266 h264_context_free(encoder->h264);
267 return -1;
268}
269
270static int shadow_encoder_init_progressive(rdpShadowEncoder* encoder)
271{
272 WINPR_ASSERT(encoder);
273 if (!encoder->progressive)
274 encoder->progressive = progressive_context_new(TRUE);
275
276 if (!encoder->progressive)
277 goto fail;
278
279 if (!progressive_context_reset(encoder->progressive))
280 goto fail;
281
282 encoder->codecs |= FREERDP_CODEC_PROGRESSIVE;
283 return 1;
284fail:
285 progressive_context_free(encoder->progressive);
286 return -1;
287}
288
289static int shadow_encoder_init(rdpShadowEncoder* encoder)
290{
291 encoder->width = encoder->server->screen->width;
292 encoder->height = encoder->server->screen->height;
293 encoder->maxTileWidth = 64;
294 encoder->maxTileHeight = 64;
295 shadow_encoder_init_grid(encoder);
296
297 if (!encoder->bs)
298 encoder->bs = Stream_New(NULL, 4ULL * encoder->maxTileWidth * encoder->maxTileHeight);
299
300 if (!encoder->bs)
301 return -1;
302
303 return 1;
304}
305
306static int shadow_encoder_uninit_rfx(rdpShadowEncoder* encoder)
307{
308 if (encoder->rfx)
309 {
310 rfx_context_free(encoder->rfx);
311 encoder->rfx = NULL;
312 }
313
314 encoder->codecs &= (UINT32)~FREERDP_CODEC_REMOTEFX;
315 return 1;
316}
317
318static int shadow_encoder_uninit_nsc(rdpShadowEncoder* encoder)
319{
320 if (encoder->nsc)
321 {
322 nsc_context_free(encoder->nsc);
323 encoder->nsc = NULL;
324 }
325
326 encoder->codecs &= (UINT32)~FREERDP_CODEC_NSCODEC;
327 return 1;
328}
329
330static int shadow_encoder_uninit_planar(rdpShadowEncoder* encoder)
331{
332 if (encoder->planar)
333 {
334 freerdp_bitmap_planar_context_free(encoder->planar);
335 encoder->planar = NULL;
336 }
337
338 encoder->codecs &= (UINT32)~FREERDP_CODEC_PLANAR;
339 return 1;
340}
341
342static int shadow_encoder_uninit_interleaved(rdpShadowEncoder* encoder)
343{
344 if (encoder->interleaved)
345 {
346 bitmap_interleaved_context_free(encoder->interleaved);
347 encoder->interleaved = NULL;
348 }
349
350 encoder->codecs &= (UINT32)~FREERDP_CODEC_INTERLEAVED;
351 return 1;
352}
353
354static int shadow_encoder_uninit_h264(rdpShadowEncoder* encoder)
355{
356 if (encoder->h264)
357 {
358 h264_context_free(encoder->h264);
359 encoder->h264 = NULL;
360 }
361
362 encoder->codecs &= (UINT32) ~(FREERDP_CODEC_AVC420 | FREERDP_CODEC_AVC444);
363 return 1;
364}
365
366static int shadow_encoder_uninit_progressive(rdpShadowEncoder* encoder)
367{
368 WINPR_ASSERT(encoder);
369 if (encoder->progressive)
370 {
371 progressive_context_free(encoder->progressive);
372 encoder->progressive = NULL;
373 }
374
375 encoder->codecs &= (UINT32)~FREERDP_CODEC_PROGRESSIVE;
376 return 1;
377}
378
379static int shadow_encoder_uninit(rdpShadowEncoder* encoder)
380{
381 shadow_encoder_uninit_grid(encoder);
382
383 if (encoder->bs)
384 {
385 Stream_Free(encoder->bs, TRUE);
386 encoder->bs = NULL;
387 }
388
389 shadow_encoder_uninit_rfx(encoder);
390
391 shadow_encoder_uninit_nsc(encoder);
392
393 shadow_encoder_uninit_planar(encoder);
394
395 shadow_encoder_uninit_interleaved(encoder);
396 shadow_encoder_uninit_h264(encoder);
397
398 shadow_encoder_uninit_progressive(encoder);
399
400 return 1;
401}
402
403int shadow_encoder_reset(rdpShadowEncoder* encoder)
404{
405 int status = 0;
406 UINT32 codecs = encoder->codecs;
407 rdpContext* context = (rdpContext*)encoder->client;
408 rdpSettings* settings = context->settings;
409 status = shadow_encoder_uninit(encoder);
410
411 if (status < 0)
412 return -1;
413
414 status = shadow_encoder_init(encoder);
415
416 if (status < 0)
417 return -1;
418
419 status = shadow_encoder_prepare(encoder, codecs);
420
421 if (status < 0)
422 return -1;
423
424 encoder->fps = 16;
425 encoder->maxFps = 32;
426 encoder->frameId = 0;
427 encoder->lastAckframeId = 0;
428 encoder->frameAck = freerdp_settings_get_bool(settings, FreeRDP_SurfaceFrameMarkerEnabled);
429 return 1;
430}
431
432int shadow_encoder_prepare(rdpShadowEncoder* encoder, UINT32 codecs)
433{
434 int status = 0;
435
436 if ((codecs & FREERDP_CODEC_REMOTEFX) && !(encoder->codecs & FREERDP_CODEC_REMOTEFX))
437 {
438 WLog_DBG(TAG, "initializing RemoteFX encoder");
439 status = shadow_encoder_init_rfx(encoder);
440
441 if (status < 0)
442 return -1;
443 }
444
445 if ((codecs & FREERDP_CODEC_NSCODEC) && !(encoder->codecs & FREERDP_CODEC_NSCODEC))
446 {
447 WLog_DBG(TAG, "initializing NSCodec encoder");
448 status = shadow_encoder_init_nsc(encoder);
449
450 if (status < 0)
451 return -1;
452 }
453
454 if ((codecs & FREERDP_CODEC_PLANAR) && !(encoder->codecs & FREERDP_CODEC_PLANAR))
455 {
456 WLog_DBG(TAG, "initializing planar bitmap encoder");
457 status = shadow_encoder_init_planar(encoder);
458
459 if (status < 0)
460 return -1;
461 }
462
463 if ((codecs & FREERDP_CODEC_INTERLEAVED) && !(encoder->codecs & FREERDP_CODEC_INTERLEAVED))
464 {
465 WLog_DBG(TAG, "initializing interleaved bitmap encoder");
466 status = shadow_encoder_init_interleaved(encoder);
467
468 if (status < 0)
469 return -1;
470 }
471
472 if ((codecs & (FREERDP_CODEC_AVC420 | FREERDP_CODEC_AVC444)) &&
473 !(encoder->codecs & (FREERDP_CODEC_AVC420 | FREERDP_CODEC_AVC444)))
474 {
475 WLog_DBG(TAG, "initializing H.264 encoder");
476 status = shadow_encoder_init_h264(encoder);
477
478 if (status < 0)
479 return -1;
480 }
481
482 if ((codecs & FREERDP_CODEC_PROGRESSIVE) && !(encoder->codecs & FREERDP_CODEC_PROGRESSIVE))
483 {
484 WLog_DBG(TAG, "initializing progressive encoder");
485 status = shadow_encoder_init_progressive(encoder);
486
487 if (status < 0)
488 return -1;
489 }
490
491 return 1;
492}
493
494rdpShadowEncoder* shadow_encoder_new(rdpShadowClient* client)
495{
496 rdpShadowEncoder* encoder = NULL;
497 rdpShadowServer* server = client->server;
498 encoder = (rdpShadowEncoder*)calloc(1, sizeof(rdpShadowEncoder));
499
500 if (!encoder)
501 return NULL;
502
503 encoder->client = client;
504 encoder->server = server;
505 encoder->fps = 16;
506 encoder->maxFps = 32;
507
508 if (shadow_encoder_init(encoder) < 0)
509 {
510 shadow_encoder_free(encoder);
511 return NULL;
512 }
513
514 return encoder;
515}
516
517void shadow_encoder_free(rdpShadowEncoder* encoder)
518{
519 if (!encoder)
520 return;
521
522 shadow_encoder_uninit(encoder);
523 free(encoder);
524}
FREERDP_API UINT32 freerdp_settings_get_uint32(const rdpSettings *settings, FreeRDP_Settings_Keys_UInt32 id)
Returns a UINT32 settings value.
FREERDP_API BOOL freerdp_settings_get_bool(const rdpSettings *settings, FreeRDP_Settings_Keys_Bool id)
Returns a boolean settings value.