FreeRDP
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Modules Pages
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 rfx_context_set_mode(encoder->rfx, freerdp_settings_get_uint32(encoder->server->settings,
144 FreeRDP_RemoteFxRlgrMode));
145 rfx_context_set_pixel_format(encoder->rfx, PIXEL_FORMAT_BGRX32);
146 encoder->codecs |= FREERDP_CODEC_REMOTEFX;
147 return 1;
148fail:
149 rfx_context_free(encoder->rfx);
150 return -1;
151}
152
153static int shadow_encoder_init_nsc(rdpShadowEncoder* encoder)
154{
155 rdpContext* context = (rdpContext*)encoder->client;
156 rdpSettings* settings = context->settings;
157
158 if (!encoder->nsc)
159 encoder->nsc = nsc_context_new();
160
161 if (!encoder->nsc)
162 goto fail;
163
164 if (!nsc_context_reset(encoder->nsc, encoder->width, encoder->height))
165 goto fail;
166
167 if (!nsc_context_set_parameters(
168 encoder->nsc, NSC_COLOR_LOSS_LEVEL,
169 freerdp_settings_get_uint32(settings, FreeRDP_NSCodecColorLossLevel)))
170 goto fail;
171 if (!nsc_context_set_parameters(
172 encoder->nsc, NSC_ALLOW_SUBSAMPLING,
173 freerdp_settings_get_bool(settings, FreeRDP_NSCodecAllowSubsampling) ? 1 : 0))
174 goto fail;
175 if (!nsc_context_set_parameters(
176 encoder->nsc, NSC_DYNAMIC_COLOR_FIDELITY,
177 !freerdp_settings_get_bool(settings, FreeRDP_NSCodecAllowDynamicColorFidelity)))
178 goto fail;
179 if (!nsc_context_set_parameters(encoder->nsc, NSC_COLOR_FORMAT, PIXEL_FORMAT_BGRX32))
180 goto fail;
181 encoder->codecs |= FREERDP_CODEC_NSCODEC;
182 return 1;
183fail:
184 nsc_context_free(encoder->nsc);
185 return -1;
186}
187
188static int shadow_encoder_init_planar(rdpShadowEncoder* encoder)
189{
190 DWORD planarFlags = 0;
191 rdpContext* context = (rdpContext*)encoder->client;
192 rdpSettings* settings = context->settings;
193
194 if (freerdp_settings_get_bool(settings, FreeRDP_DrawAllowSkipAlpha))
195 planarFlags |= PLANAR_FORMAT_HEADER_NA;
196
197 planarFlags |= PLANAR_FORMAT_HEADER_RLE;
198
199 if (!encoder->planar)
200 {
201 encoder->planar = freerdp_bitmap_planar_context_new(planarFlags, encoder->maxTileWidth,
202 encoder->maxTileHeight);
203 }
204
205 if (!encoder->planar)
206 goto fail;
207
208 if (!freerdp_bitmap_planar_context_reset(encoder->planar, encoder->maxTileWidth,
209 encoder->maxTileHeight))
210 goto fail;
211
212 encoder->codecs |= FREERDP_CODEC_PLANAR;
213 return 1;
214fail:
215 freerdp_bitmap_planar_context_free(encoder->planar);
216 return -1;
217}
218
219static int shadow_encoder_init_interleaved(rdpShadowEncoder* encoder)
220{
221 if (!encoder->interleaved)
222 encoder->interleaved = bitmap_interleaved_context_new(TRUE);
223
224 if (!encoder->interleaved)
225 goto fail;
226
227 if (!bitmap_interleaved_context_reset(encoder->interleaved))
228 goto fail;
229
230 encoder->codecs |= FREERDP_CODEC_INTERLEAVED;
231 return 1;
232fail:
233 bitmap_interleaved_context_free(encoder->interleaved);
234 return -1;
235}
236
237static int shadow_encoder_init_h264(rdpShadowEncoder* encoder)
238{
239 if (!encoder->h264)
240 encoder->h264 = h264_context_new(TRUE);
241
242 if (!encoder->h264)
243 goto fail;
244
245 if (!h264_context_reset(encoder->h264, encoder->width, encoder->height))
246 goto fail;
247
248 if (!h264_context_set_option(encoder->h264, H264_CONTEXT_OPTION_RATECONTROL,
249 encoder->server->h264RateControlMode))
250 goto fail;
251 if (!h264_context_set_option(encoder->h264, H264_CONTEXT_OPTION_BITRATE,
252 encoder->server->h264BitRate))
253 goto fail;
254 if (!h264_context_set_option(encoder->h264, H264_CONTEXT_OPTION_FRAMERATE,
255 encoder->server->h264FrameRate))
256 goto fail;
257 if (!h264_context_set_option(encoder->h264, H264_CONTEXT_OPTION_QP, encoder->server->h264QP))
258 goto fail;
259
260 encoder->codecs |= FREERDP_CODEC_AVC420 | FREERDP_CODEC_AVC444;
261 return 1;
262fail:
263 h264_context_free(encoder->h264);
264 return -1;
265}
266
267static int shadow_encoder_init_progressive(rdpShadowEncoder* encoder)
268{
269 WINPR_ASSERT(encoder);
270 if (!encoder->progressive)
271 encoder->progressive = progressive_context_new(TRUE);
272
273 if (!encoder->progressive)
274 goto fail;
275
276 if (!progressive_context_reset(encoder->progressive))
277 goto fail;
278
279 encoder->codecs |= FREERDP_CODEC_PROGRESSIVE;
280 return 1;
281fail:
282 progressive_context_free(encoder->progressive);
283 return -1;
284}
285
286static int shadow_encoder_init(rdpShadowEncoder* encoder)
287{
288 encoder->width = encoder->server->screen->width;
289 encoder->height = encoder->server->screen->height;
290 encoder->maxTileWidth = 64;
291 encoder->maxTileHeight = 64;
292 shadow_encoder_init_grid(encoder);
293
294 if (!encoder->bs)
295 encoder->bs = Stream_New(NULL, 4ULL * encoder->maxTileWidth * encoder->maxTileHeight);
296
297 if (!encoder->bs)
298 return -1;
299
300 return 1;
301}
302
303static int shadow_encoder_uninit_rfx(rdpShadowEncoder* encoder)
304{
305 if (encoder->rfx)
306 {
307 rfx_context_free(encoder->rfx);
308 encoder->rfx = NULL;
309 }
310
311 encoder->codecs &= (UINT32)~FREERDP_CODEC_REMOTEFX;
312 return 1;
313}
314
315static int shadow_encoder_uninit_nsc(rdpShadowEncoder* encoder)
316{
317 if (encoder->nsc)
318 {
319 nsc_context_free(encoder->nsc);
320 encoder->nsc = NULL;
321 }
322
323 encoder->codecs &= (UINT32)~FREERDP_CODEC_NSCODEC;
324 return 1;
325}
326
327static int shadow_encoder_uninit_planar(rdpShadowEncoder* encoder)
328{
329 if (encoder->planar)
330 {
331 freerdp_bitmap_planar_context_free(encoder->planar);
332 encoder->planar = NULL;
333 }
334
335 encoder->codecs &= (UINT32)~FREERDP_CODEC_PLANAR;
336 return 1;
337}
338
339static int shadow_encoder_uninit_interleaved(rdpShadowEncoder* encoder)
340{
341 if (encoder->interleaved)
342 {
343 bitmap_interleaved_context_free(encoder->interleaved);
344 encoder->interleaved = NULL;
345 }
346
347 encoder->codecs &= (UINT32)~FREERDP_CODEC_INTERLEAVED;
348 return 1;
349}
350
351static int shadow_encoder_uninit_h264(rdpShadowEncoder* encoder)
352{
353 if (encoder->h264)
354 {
355 h264_context_free(encoder->h264);
356 encoder->h264 = NULL;
357 }
358
359 encoder->codecs &= (UINT32) ~(FREERDP_CODEC_AVC420 | FREERDP_CODEC_AVC444);
360 return 1;
361}
362
363static int shadow_encoder_uninit_progressive(rdpShadowEncoder* encoder)
364{
365 WINPR_ASSERT(encoder);
366 if (encoder->progressive)
367 {
368 progressive_context_free(encoder->progressive);
369 encoder->progressive = NULL;
370 }
371
372 encoder->codecs &= (UINT32)~FREERDP_CODEC_PROGRESSIVE;
373 return 1;
374}
375
376static int shadow_encoder_uninit(rdpShadowEncoder* encoder)
377{
378 shadow_encoder_uninit_grid(encoder);
379
380 if (encoder->bs)
381 {
382 Stream_Free(encoder->bs, TRUE);
383 encoder->bs = NULL;
384 }
385
386 shadow_encoder_uninit_rfx(encoder);
387
388 shadow_encoder_uninit_nsc(encoder);
389
390 shadow_encoder_uninit_planar(encoder);
391
392 shadow_encoder_uninit_interleaved(encoder);
393 shadow_encoder_uninit_h264(encoder);
394
395 shadow_encoder_uninit_progressive(encoder);
396
397 return 1;
398}
399
400int shadow_encoder_reset(rdpShadowEncoder* encoder)
401{
402 int status = 0;
403 UINT32 codecs = encoder->codecs;
404 rdpContext* context = (rdpContext*)encoder->client;
405 rdpSettings* settings = context->settings;
406 status = shadow_encoder_uninit(encoder);
407
408 if (status < 0)
409 return -1;
410
411 status = shadow_encoder_init(encoder);
412
413 if (status < 0)
414 return -1;
415
416 status = shadow_encoder_prepare(encoder, codecs);
417
418 if (status < 0)
419 return -1;
420
421 encoder->fps = 16;
422 encoder->maxFps = 32;
423 encoder->frameId = 0;
424 encoder->lastAckframeId = 0;
425 encoder->frameAck = freerdp_settings_get_bool(settings, FreeRDP_SurfaceFrameMarkerEnabled);
426 return 1;
427}
428
429int shadow_encoder_prepare(rdpShadowEncoder* encoder, UINT32 codecs)
430{
431 int status = 0;
432
433 if ((codecs & FREERDP_CODEC_REMOTEFX) && !(encoder->codecs & FREERDP_CODEC_REMOTEFX))
434 {
435 WLog_DBG(TAG, "initializing RemoteFX encoder");
436 status = shadow_encoder_init_rfx(encoder);
437
438 if (status < 0)
439 return -1;
440 }
441
442 if ((codecs & FREERDP_CODEC_NSCODEC) && !(encoder->codecs & FREERDP_CODEC_NSCODEC))
443 {
444 WLog_DBG(TAG, "initializing NSCodec encoder");
445 status = shadow_encoder_init_nsc(encoder);
446
447 if (status < 0)
448 return -1;
449 }
450
451 if ((codecs & FREERDP_CODEC_PLANAR) && !(encoder->codecs & FREERDP_CODEC_PLANAR))
452 {
453 WLog_DBG(TAG, "initializing planar bitmap encoder");
454 status = shadow_encoder_init_planar(encoder);
455
456 if (status < 0)
457 return -1;
458 }
459
460 if ((codecs & FREERDP_CODEC_INTERLEAVED) && !(encoder->codecs & FREERDP_CODEC_INTERLEAVED))
461 {
462 WLog_DBG(TAG, "initializing interleaved bitmap encoder");
463 status = shadow_encoder_init_interleaved(encoder);
464
465 if (status < 0)
466 return -1;
467 }
468
469 if ((codecs & (FREERDP_CODEC_AVC420 | FREERDP_CODEC_AVC444)) &&
470 !(encoder->codecs & (FREERDP_CODEC_AVC420 | FREERDP_CODEC_AVC444)))
471 {
472 WLog_DBG(TAG, "initializing H.264 encoder");
473 status = shadow_encoder_init_h264(encoder);
474
475 if (status < 0)
476 return -1;
477 }
478
479 if ((codecs & FREERDP_CODEC_PROGRESSIVE) && !(encoder->codecs & FREERDP_CODEC_PROGRESSIVE))
480 {
481 WLog_DBG(TAG, "initializing progressive encoder");
482 status = shadow_encoder_init_progressive(encoder);
483
484 if (status < 0)
485 return -1;
486 }
487
488 return 1;
489}
490
491rdpShadowEncoder* shadow_encoder_new(rdpShadowClient* client)
492{
493 rdpShadowEncoder* encoder = NULL;
494 rdpShadowServer* server = client->server;
495 encoder = (rdpShadowEncoder*)calloc(1, sizeof(rdpShadowEncoder));
496
497 if (!encoder)
498 return NULL;
499
500 encoder->client = client;
501 encoder->server = server;
502 encoder->fps = 16;
503 encoder->maxFps = 32;
504
505 if (shadow_encoder_init(encoder) < 0)
506 {
507 shadow_encoder_free(encoder);
508 return NULL;
509 }
510
511 return encoder;
512}
513
514void shadow_encoder_free(rdpShadowEncoder* encoder)
515{
516 if (!encoder)
517 return;
518
519 shadow_encoder_uninit(encoder);
520 free(encoder);
521}
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.