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