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 if (encoder->queueDepth == SUSPEND_FRAME_ACKNOWLEDGEMENT)
48 return 0;
49 if (encoder->lastAckframeId > encoder->frameId)
50 return 1;
51 return encoder->frameId - encoder->lastAckframeId;
52}
53
54UINT32 shadow_encoder_create_frame_id(rdpShadowEncoder* encoder)
55{
56 const UINT64 inFlightFrames = shadow_encoder_inflight_frames(encoder);
57
58 /*
59 * Calculate preferred fps according to how much frames are
60 * in-progress. Note that it only works when subsystem implementation
61 * calls shadow_encoder_preferred_fps and takes the suggestion.
62 */
63 if (inFlightFrames > 1)
64 {
65 UINT64 fps = (100 / (inFlightFrames + 1) * encoder->maxFps) / 100;
66 if (fps > encoder->maxFps)
67 fps = encoder->maxFps;
68 encoder->fps = WINPR_ASSERTING_INT_CAST(UINT32, fps);
69 }
70 else
71 {
72 encoder->fps += 2;
73
74 if (encoder->fps > encoder->maxFps)
75 encoder->fps = encoder->maxFps;
76 }
77
78 if (encoder->fps < 1)
79 encoder->fps = 1;
80
81 const UINT32 frameId = ++encoder->frameId;
82 return frameId;
83}
84
85WINPR_ATTR_NODISCARD
86static int shadow_encoder_init_grid(rdpShadowEncoder* encoder)
87{
88 UINT32 tileSize = 0;
89 UINT32 tileCount = 0;
90 encoder->gridWidth = ((encoder->width + (encoder->maxTileWidth - 1)) / encoder->maxTileWidth);
91 encoder->gridHeight =
92 ((encoder->height + (encoder->maxTileHeight - 1)) / encoder->maxTileHeight);
93 tileSize = encoder->maxTileWidth * encoder->maxTileHeight * 4;
94 tileCount = encoder->gridWidth * encoder->gridHeight;
95 encoder->gridBuffer = (BYTE*)calloc(tileSize, tileCount);
96
97 if (!encoder->gridBuffer)
98 return -1;
99
100 encoder->grid = (BYTE**)calloc(tileCount, sizeof(BYTE*));
101
102 if (!encoder->grid)
103 return -1;
104
105 for (UINT32 i = 0; i < encoder->gridHeight; i++)
106 {
107 for (UINT32 j = 0; j < encoder->gridWidth; j++)
108 {
109 const size_t k = (1ULL * i * encoder->gridWidth) + j;
110 encoder->grid[k] = &(encoder->gridBuffer[k * tileSize]);
111 }
112 }
113
114 return 0;
115}
116
117static int shadow_encoder_uninit_grid(rdpShadowEncoder* encoder)
118{
119 if (encoder->gridBuffer)
120 {
121 free(encoder->gridBuffer);
122 encoder->gridBuffer = nullptr;
123 }
124
125 if (encoder->grid)
126 {
127 free((void*)encoder->grid);
128 encoder->grid = nullptr;
129 }
130
131 encoder->gridWidth = 0;
132 encoder->gridHeight = 0;
133 return 0;
134}
135
136WINPR_ATTR_NODISCARD
137static int shadow_encoder_init_rfx(rdpShadowEncoder* encoder)
138{
139 if (!encoder->rfx)
140 encoder->rfx = rfx_context_new_ex(
141 TRUE, freerdp_settings_get_uint32(encoder->server->settings, FreeRDP_ThreadingFlags));
142
143 if (!encoder->rfx)
144 goto fail;
145
146 if (!rfx_context_reset(encoder->rfx, encoder->width, encoder->height))
147 goto fail;
148
149 {
150 const UINT32 mode =
151 freerdp_settings_get_uint32(encoder->server->settings, FreeRDP_RemoteFxRlgrMode);
152 if (!rfx_context_set_mode(encoder->rfx, WINPR_ASSERTING_INT_CAST(RLGR_MODE, mode)))
153 goto fail;
154 }
155 rfx_context_set_pixel_format(encoder->rfx, PIXEL_FORMAT_BGRX32);
156 encoder->codecs |= FREERDP_CODEC_REMOTEFX;
157 return 1;
158fail:
159 rfx_context_free(encoder->rfx);
160 encoder->rfx = nullptr;
161 return -1;
162}
163
164WINPR_ATTR_NODISCARD
165static int shadow_encoder_init_nsc(rdpShadowEncoder* encoder)
166{
167 rdpContext* context = (rdpContext*)encoder->client;
168 rdpSettings* settings = context->settings;
169
170 if (!encoder->nsc)
171 encoder->nsc = nsc_context_new();
172
173 if (!encoder->nsc)
174 goto fail;
175
176 if (!nsc_context_reset(encoder->nsc, encoder->width, encoder->height))
177 goto fail;
178
179 if (!nsc_context_set_parameters(
180 encoder->nsc, NSC_COLOR_LOSS_LEVEL,
181 freerdp_settings_get_uint32(settings, FreeRDP_NSCodecColorLossLevel)))
182 goto fail;
183 if (!nsc_context_set_parameters(
184 encoder->nsc, NSC_ALLOW_SUBSAMPLING,
185 freerdp_settings_get_bool(settings, FreeRDP_NSCodecAllowSubsampling) ? 1 : 0))
186 goto fail;
187 if (!nsc_context_set_parameters(
188 encoder->nsc, NSC_DYNAMIC_COLOR_FIDELITY,
189 !freerdp_settings_get_bool(settings, FreeRDP_NSCodecAllowDynamicColorFidelity)))
190 goto fail;
191 if (!nsc_context_set_parameters(encoder->nsc, NSC_COLOR_FORMAT, PIXEL_FORMAT_BGRX32))
192 goto fail;
193 encoder->codecs |= FREERDP_CODEC_NSCODEC;
194 return 1;
195fail:
196 nsc_context_free(encoder->nsc);
197 return -1;
198}
199
200WINPR_ATTR_NODISCARD
201static int shadow_encoder_init_planar(rdpShadowEncoder* encoder)
202{
203 DWORD planarFlags = 0;
204 rdpContext* context = (rdpContext*)encoder->client;
205 rdpSettings* settings = context->settings;
206
207 if (freerdp_settings_get_bool(settings, FreeRDP_DrawAllowSkipAlpha))
208 planarFlags |= PLANAR_FORMAT_HEADER_NA;
209
210 planarFlags |= PLANAR_FORMAT_HEADER_RLE;
211
212 if (!encoder->planar)
213 {
214 encoder->planar = freerdp_bitmap_planar_context_new(planarFlags, encoder->maxTileWidth,
215 encoder->maxTileHeight);
216 }
217
218 if (!encoder->planar)
219 goto fail;
220
221 if (!freerdp_bitmap_planar_context_reset(encoder->planar, encoder->maxTileWidth,
222 encoder->maxTileHeight))
223 goto fail;
224
225 encoder->codecs |= FREERDP_CODEC_PLANAR;
226 return 1;
227fail:
228 freerdp_bitmap_planar_context_free(encoder->planar);
229 return -1;
230}
231
232WINPR_ATTR_NODISCARD
233static int shadow_encoder_init_interleaved(rdpShadowEncoder* encoder)
234{
235 if (!encoder->interleaved)
236 encoder->interleaved = bitmap_interleaved_context_new(TRUE);
237
238 if (!encoder->interleaved)
239 goto fail;
240
241 if (!bitmap_interleaved_context_reset(encoder->interleaved))
242 goto fail;
243
244 encoder->codecs |= FREERDP_CODEC_INTERLEAVED;
245 return 1;
246fail:
247 bitmap_interleaved_context_free(encoder->interleaved);
248 return -1;
249}
250
251WINPR_ATTR_NODISCARD
252static int shadow_encoder_init_h264(rdpShadowEncoder* encoder)
253{
254 if (!encoder->h264)
255 encoder->h264 = h264_context_new(TRUE);
256
257 if (!encoder->h264)
258 goto fail;
259
260 if (!h264_context_reset(encoder->h264, encoder->width, encoder->height))
261 goto fail;
262
263 if (!h264_context_set_option(encoder->h264, H264_CONTEXT_OPTION_RATECONTROL,
264 encoder->server->h264RateControlMode))
265 goto fail;
266 if (!h264_context_set_option(encoder->h264, H264_CONTEXT_OPTION_BITRATE,
267 encoder->server->h264BitRate))
268 goto fail;
269 if (!h264_context_set_option(encoder->h264, H264_CONTEXT_OPTION_FRAMERATE,
270 encoder->server->h264FrameRate))
271 goto fail;
272 if (!h264_context_set_option(encoder->h264, H264_CONTEXT_OPTION_QP, encoder->server->h264QP))
273 goto fail;
274 if (!h264_context_set_option(encoder->h264, H264_CONTEXT_OPTION_HW_ACCEL,
275 (UINT32)encoder->server->h264HwAccel))
276 goto fail;
277
278 encoder->codecs |= FREERDP_CODEC_AVC420 | FREERDP_CODEC_AVC444;
279 return 1;
280fail:
281 h264_context_free(encoder->h264);
282 return -1;
283}
284
285#if defined(WITH_GFX_AV1)
286WINPR_ATTR_NODISCARD
287static int shadow_encoder_init_av1(rdpShadowEncoder* encoder, UINT32 codecs)
288{
289 WINPR_ASSERT(encoder);
290
291 UINT32 profile = 0;
292 if ((codecs & FREERDP_CODEC_AV1_I444) != 0)
293 profile = 1;
294
295 if (!encoder->av1)
296 encoder->av1 = freerdp_av1_context_new(TRUE);
297
298 if (!encoder->av1)
299 goto fail;
300
301 if (!freerdp_av1_context_reset(encoder->av1, encoder->width, encoder->height))
302 goto fail;
303
304 if (!freerdp_av1_context_set_option(encoder->av1, FREERDP_AV1_CONTEXT_OPTION_PROFILE, profile))
305 goto fail;
306
307 if (!freerdp_av1_context_set_option(encoder->av1, FREERDP_AV1_CONTEXT_OPTION_RATECONTROL,
308 encoder->server->AV1RateControlMode))
309 goto fail;
310 if (!freerdp_av1_context_set_option(encoder->av1, FREERDP_AV1_CONTEXT_OPTION_BITRATE,
311 encoder->server->AV1BitRate))
312 goto fail;
313
314 encoder->codecs &= ~(FREERDP_CODEC_AV1_I420 | FREERDP_CODEC_AV1_I444);
315 encoder->codecs |= codecs;
316 return 1;
317fail:
318 freerdp_av1_context_free(encoder->av1);
319 encoder->av1 = nullptr;
320 return -1;
321}
322#endif
323
324WINPR_ATTR_NODISCARD
325static int shadow_encoder_init_progressive(rdpShadowEncoder* encoder)
326{
327 WINPR_ASSERT(encoder);
328 if (!encoder->progressive)
329 encoder->progressive = progressive_context_new(TRUE);
330
331 if (!encoder->progressive)
332 goto fail;
333
334 if (!progressive_context_reset(encoder->progressive))
335 goto fail;
336
337 encoder->codecs |= FREERDP_CODEC_PROGRESSIVE;
338 return 1;
339fail:
340 progressive_context_free(encoder->progressive);
341 return -1;
342}
343
344WINPR_ATTR_NODISCARD
345static int shadow_encoder_init(rdpShadowEncoder* encoder)
346{
347 encoder->width = encoder->server->screen->width;
348 encoder->height = encoder->server->screen->height;
349 encoder->maxTileWidth = 64;
350 encoder->maxTileHeight = 64;
351 if (shadow_encoder_init_grid(encoder) < 0)
352 return -1;
353
354 if (!encoder->bs)
355 encoder->bs = Stream_New(nullptr, 4ULL * encoder->maxTileWidth * encoder->maxTileHeight);
356
357 if (!encoder->bs)
358 return -1;
359
360 return 1;
361}
362
363static int shadow_encoder_uninit_rfx(rdpShadowEncoder* encoder)
364{
365 if (encoder->rfx)
366 {
367 rfx_context_free(encoder->rfx);
368 encoder->rfx = nullptr;
369 }
370
371 encoder->codecs &= (UINT32)~FREERDP_CODEC_REMOTEFX;
372 return 1;
373}
374
375static int shadow_encoder_uninit_nsc(rdpShadowEncoder* encoder)
376{
377 if (encoder->nsc)
378 {
379 nsc_context_free(encoder->nsc);
380 encoder->nsc = nullptr;
381 }
382
383 encoder->codecs &= (UINT32)~FREERDP_CODEC_NSCODEC;
384 return 1;
385}
386
387static int shadow_encoder_uninit_planar(rdpShadowEncoder* encoder)
388{
389 if (encoder->planar)
390 {
391 freerdp_bitmap_planar_context_free(encoder->planar);
392 encoder->planar = nullptr;
393 }
394
395 encoder->codecs &= (UINT32)~FREERDP_CODEC_PLANAR;
396 return 1;
397}
398
399static int shadow_encoder_uninit_interleaved(rdpShadowEncoder* encoder)
400{
401 if (encoder->interleaved)
402 {
403 bitmap_interleaved_context_free(encoder->interleaved);
404 encoder->interleaved = nullptr;
405 }
406
407 encoder->codecs &= (UINT32)~FREERDP_CODEC_INTERLEAVED;
408 return 1;
409}
410
411static int shadow_encoder_uninit_h264(rdpShadowEncoder* encoder)
412{
413 if (encoder->h264)
414 {
415 h264_context_free(encoder->h264);
416 encoder->h264 = nullptr;
417 }
418
419 encoder->codecs &= (UINT32) ~(FREERDP_CODEC_AVC420 | FREERDP_CODEC_AVC444);
420 return 1;
421}
422
423#if defined(WITH_GFX_AV1)
424static int shadow_encoder_uninit_av1(rdpShadowEncoder* encoder)
425{
426 WINPR_ASSERT(encoder);
427
428 freerdp_av1_context_free(encoder->av1);
429 encoder->av1 = nullptr;
430
431 encoder->codecs &= (UINT32) ~(FREERDP_CODEC_AV1_I420 | FREERDP_CODEC_AV1_I444);
432 return 1;
433}
434#endif
435
436static int shadow_encoder_uninit_progressive(rdpShadowEncoder* encoder)
437{
438 WINPR_ASSERT(encoder);
439 if (encoder->progressive)
440 {
441 progressive_context_free(encoder->progressive);
442 encoder->progressive = nullptr;
443 }
444
445 encoder->codecs &= (UINT32)~FREERDP_CODEC_PROGRESSIVE;
446 return 1;
447}
448
449static int shadow_encoder_uninit(rdpShadowEncoder* encoder)
450{
451 shadow_encoder_uninit_grid(encoder);
452
453 if (encoder->bs)
454 {
455 Stream_Free(encoder->bs, TRUE);
456 encoder->bs = nullptr;
457 }
458
459 shadow_encoder_uninit_rfx(encoder);
460
461 shadow_encoder_uninit_nsc(encoder);
462
463 shadow_encoder_uninit_planar(encoder);
464
465 shadow_encoder_uninit_interleaved(encoder);
466 shadow_encoder_uninit_h264(encoder);
467#if defined(WITH_GFX_AV1)
468 shadow_encoder_uninit_av1(encoder);
469#endif
470
471 shadow_encoder_uninit_progressive(encoder);
472
473 return 1;
474}
475
476int shadow_encoder_reset(rdpShadowEncoder* encoder)
477{
478 int status = 0;
479 UINT32 codecs = encoder->codecs;
480 rdpContext* context = (rdpContext*)encoder->client;
481 rdpSettings* settings = context->settings;
482 status = shadow_encoder_uninit(encoder);
483
484 if (status < 0)
485 return -1;
486
487 status = shadow_encoder_init(encoder);
488
489 if (status < 0)
490 return -1;
491
492 status = shadow_encoder_prepare(encoder, codecs);
493
494 if (status < 0)
495 return -1;
496
497 encoder->fps = 16;
498 encoder->maxFps = 32;
499 encoder->frameId = 0;
500 encoder->lastAckframeId = 0;
501 encoder->frameAck = freerdp_settings_get_bool(settings, FreeRDP_SurfaceFrameMarkerEnabled);
502 return 1;
503}
504
505int shadow_encoder_prepare(rdpShadowEncoder* encoder, UINT32 codecs)
506{
507 int status = 0;
508
509 if ((codecs & FREERDP_CODEC_REMOTEFX) && !(encoder->codecs & FREERDP_CODEC_REMOTEFX))
510 {
511 WLog_DBG(TAG, "initializing RemoteFX encoder");
512 status = shadow_encoder_init_rfx(encoder);
513
514 if (status < 0)
515 return -1;
516 }
517
518 if ((codecs & FREERDP_CODEC_NSCODEC) && !(encoder->codecs & FREERDP_CODEC_NSCODEC))
519 {
520 WLog_DBG(TAG, "initializing NSCodec encoder");
521 status = shadow_encoder_init_nsc(encoder);
522
523 if (status < 0)
524 return -1;
525 }
526
527 if ((codecs & FREERDP_CODEC_PLANAR) && !(encoder->codecs & FREERDP_CODEC_PLANAR))
528 {
529 WLog_DBG(TAG, "initializing planar bitmap encoder");
530 status = shadow_encoder_init_planar(encoder);
531
532 if (status < 0)
533 return -1;
534 }
535
536 if ((codecs & FREERDP_CODEC_INTERLEAVED) && !(encoder->codecs & FREERDP_CODEC_INTERLEAVED))
537 {
538 WLog_DBG(TAG, "initializing interleaved bitmap encoder");
539 status = shadow_encoder_init_interleaved(encoder);
540
541 if (status < 0)
542 return -1;
543 }
544
545 if ((codecs & (FREERDP_CODEC_AVC420 | FREERDP_CODEC_AVC444)) &&
546 !(encoder->codecs & (FREERDP_CODEC_AVC420 | FREERDP_CODEC_AVC444)))
547 {
548 WLog_DBG(TAG, "initializing H.264 encoder");
549 status = shadow_encoder_init_h264(encoder);
550
551 if (status < 0)
552 return -1;
553 }
554
555 if ((codecs & FREERDP_CODEC_PROGRESSIVE) && !(encoder->codecs & FREERDP_CODEC_PROGRESSIVE))
556 {
557 WLog_DBG(TAG, "initializing progressive encoder");
558 status = shadow_encoder_init_progressive(encoder);
559
560 if (status < 0)
561 return -1;
562 }
563
564#if defined(WITH_GFX_AV1)
565 const UINT32 cmask = codecs & (FREERDP_CODEC_AV1_I420 | FREERDP_CODEC_AV1_I444);
566 const UINT32 emask = encoder->codecs & (FREERDP_CODEC_AV1_I420 | FREERDP_CODEC_AV1_I444);
567 if (cmask != emask)
568 {
569 WLog_DBG(TAG, "initializing AV1 encoder");
570 status = shadow_encoder_init_av1(encoder, codecs);
571
572 if (status < 0)
573 return -1;
574 }
575#endif
576
577 return 1;
578}
579
580rdpShadowEncoder* shadow_encoder_new(rdpShadowClient* client)
581{
582 rdpShadowEncoder* encoder = nullptr;
583 rdpShadowServer* server = client->server;
584 encoder = (rdpShadowEncoder*)calloc(1, sizeof(rdpShadowEncoder));
585
586 if (!encoder)
587 return nullptr;
588
589 encoder->client = client;
590 encoder->server = server;
591 encoder->fps = 16;
592 encoder->maxFps = 32;
593
594 if (shadow_encoder_init(encoder) < 0)
595 {
596 shadow_encoder_free(encoder);
597 return nullptr;
598 }
599
600 return encoder;
601}
602
603void shadow_encoder_free(rdpShadowEncoder* encoder)
604{
605 if (!encoder)
606 return;
607
608 shadow_encoder_uninit(encoder);
609 free(encoder);
610}
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.