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 encoder->rfx = nullptr;
157 return -1;
158}
159
160WINPR_ATTR_NODISCARD
161static int shadow_encoder_init_nsc(rdpShadowEncoder* encoder)
162{
163 rdpContext* context = (rdpContext*)encoder->client;
164 rdpSettings* settings = context->settings;
165
166 if (!encoder->nsc)
167 encoder->nsc = nsc_context_new();
168
169 if (!encoder->nsc)
170 goto fail;
171
172 if (!nsc_context_reset(encoder->nsc, encoder->width, encoder->height))
173 goto fail;
174
175 if (!nsc_context_set_parameters(
176 encoder->nsc, NSC_COLOR_LOSS_LEVEL,
177 freerdp_settings_get_uint32(settings, FreeRDP_NSCodecColorLossLevel)))
178 goto fail;
179 if (!nsc_context_set_parameters(
180 encoder->nsc, NSC_ALLOW_SUBSAMPLING,
181 freerdp_settings_get_bool(settings, FreeRDP_NSCodecAllowSubsampling) ? 1 : 0))
182 goto fail;
183 if (!nsc_context_set_parameters(
184 encoder->nsc, NSC_DYNAMIC_COLOR_FIDELITY,
185 !freerdp_settings_get_bool(settings, FreeRDP_NSCodecAllowDynamicColorFidelity)))
186 goto fail;
187 if (!nsc_context_set_parameters(encoder->nsc, NSC_COLOR_FORMAT, PIXEL_FORMAT_BGRX32))
188 goto fail;
189 encoder->codecs |= FREERDP_CODEC_NSCODEC;
190 return 1;
191fail:
192 nsc_context_free(encoder->nsc);
193 return -1;
194}
195
196WINPR_ATTR_NODISCARD
197static int shadow_encoder_init_planar(rdpShadowEncoder* encoder)
198{
199 DWORD planarFlags = 0;
200 rdpContext* context = (rdpContext*)encoder->client;
201 rdpSettings* settings = context->settings;
202
203 if (freerdp_settings_get_bool(settings, FreeRDP_DrawAllowSkipAlpha))
204 planarFlags |= PLANAR_FORMAT_HEADER_NA;
205
206 planarFlags |= PLANAR_FORMAT_HEADER_RLE;
207
208 if (!encoder->planar)
209 {
210 encoder->planar = freerdp_bitmap_planar_context_new(planarFlags, encoder->maxTileWidth,
211 encoder->maxTileHeight);
212 }
213
214 if (!encoder->planar)
215 goto fail;
216
217 if (!freerdp_bitmap_planar_context_reset(encoder->planar, encoder->maxTileWidth,
218 encoder->maxTileHeight))
219 goto fail;
220
221 encoder->codecs |= FREERDP_CODEC_PLANAR;
222 return 1;
223fail:
224 freerdp_bitmap_planar_context_free(encoder->planar);
225 return -1;
226}
227
228WINPR_ATTR_NODISCARD
229static int shadow_encoder_init_interleaved(rdpShadowEncoder* encoder)
230{
231 if (!encoder->interleaved)
232 encoder->interleaved = bitmap_interleaved_context_new(TRUE);
233
234 if (!encoder->interleaved)
235 goto fail;
236
237 if (!bitmap_interleaved_context_reset(encoder->interleaved))
238 goto fail;
239
240 encoder->codecs |= FREERDP_CODEC_INTERLEAVED;
241 return 1;
242fail:
243 bitmap_interleaved_context_free(encoder->interleaved);
244 return -1;
245}
246
247WINPR_ATTR_NODISCARD
248static int shadow_encoder_init_h264(rdpShadowEncoder* encoder)
249{
250 if (!encoder->h264)
251 encoder->h264 = h264_context_new(TRUE);
252
253 if (!encoder->h264)
254 goto fail;
255
256 if (!h264_context_reset(encoder->h264, encoder->width, encoder->height))
257 goto fail;
258
259 if (!h264_context_set_option(encoder->h264, H264_CONTEXT_OPTION_RATECONTROL,
260 encoder->server->h264RateControlMode))
261 goto fail;
262 if (!h264_context_set_option(encoder->h264, H264_CONTEXT_OPTION_BITRATE,
263 encoder->server->h264BitRate))
264 goto fail;
265 if (!h264_context_set_option(encoder->h264, H264_CONTEXT_OPTION_FRAMERATE,
266 encoder->server->h264FrameRate))
267 goto fail;
268 if (!h264_context_set_option(encoder->h264, H264_CONTEXT_OPTION_QP, encoder->server->h264QP))
269 goto fail;
270 if (!h264_context_set_option(encoder->h264, H264_CONTEXT_OPTION_HW_ACCEL,
271 (UINT32)encoder->server->h264HwAccel))
272 goto fail;
273
274 encoder->codecs |= FREERDP_CODEC_AVC420 | FREERDP_CODEC_AVC444;
275 return 1;
276fail:
277 h264_context_free(encoder->h264);
278 return -1;
279}
280
281#if defined(WITH_GFX_AV1)
282WINPR_ATTR_NODISCARD
283static int shadow_encoder_init_av1(rdpShadowEncoder* encoder, UINT32 codecs)
284{
285 WINPR_ASSERT(encoder);
286
287 UINT32 profile = 0;
288 if ((codecs & FREERDP_CODEC_AV1_I444) != 0)
289 profile = 1;
290
291 if (!encoder->av1)
292 encoder->av1 = freerdp_av1_context_new(TRUE);
293
294 if (!encoder->av1)
295 goto fail;
296
297 if (!freerdp_av1_context_reset(encoder->av1, encoder->width, encoder->height))
298 goto fail;
299
300 if (!freerdp_av1_context_set_option(encoder->av1, FREERDP_AV1_CONTEXT_OPTION_PROFILE, profile))
301 goto fail;
302
303 if (!freerdp_av1_context_set_option(encoder->av1, FREERDP_AV1_CONTEXT_OPTION_RATECONTROL,
304 encoder->server->AV1RateControlMode))
305 goto fail;
306 if (!freerdp_av1_context_set_option(encoder->av1, FREERDP_AV1_CONTEXT_OPTION_BITRATE,
307 encoder->server->AV1BitRate))
308 goto fail;
309
310 encoder->codecs &= ~(FREERDP_CODEC_AV1_I420 | FREERDP_CODEC_AV1_I444);
311 encoder->codecs |= codecs;
312 return 1;
313fail:
314 freerdp_av1_context_free(encoder->av1);
315 encoder->av1 = nullptr;
316 return -1;
317}
318#endif
319
320WINPR_ATTR_NODISCARD
321static int shadow_encoder_init_progressive(rdpShadowEncoder* encoder)
322{
323 WINPR_ASSERT(encoder);
324 if (!encoder->progressive)
325 encoder->progressive = progressive_context_new(TRUE);
326
327 if (!encoder->progressive)
328 goto fail;
329
330 if (!progressive_context_reset(encoder->progressive))
331 goto fail;
332
333 encoder->codecs |= FREERDP_CODEC_PROGRESSIVE;
334 return 1;
335fail:
336 progressive_context_free(encoder->progressive);
337 return -1;
338}
339
340WINPR_ATTR_NODISCARD
341static int shadow_encoder_init(rdpShadowEncoder* encoder)
342{
343 encoder->width = encoder->server->screen->width;
344 encoder->height = encoder->server->screen->height;
345 encoder->maxTileWidth = 64;
346 encoder->maxTileHeight = 64;
347 if (shadow_encoder_init_grid(encoder) < 0)
348 return -1;
349
350 if (!encoder->bs)
351 encoder->bs = Stream_New(nullptr, 4ULL * encoder->maxTileWidth * encoder->maxTileHeight);
352
353 if (!encoder->bs)
354 return -1;
355
356 return 1;
357}
358
359static int shadow_encoder_uninit_rfx(rdpShadowEncoder* encoder)
360{
361 if (encoder->rfx)
362 {
363 rfx_context_free(encoder->rfx);
364 encoder->rfx = nullptr;
365 }
366
367 encoder->codecs &= (UINT32)~FREERDP_CODEC_REMOTEFX;
368 return 1;
369}
370
371static int shadow_encoder_uninit_nsc(rdpShadowEncoder* encoder)
372{
373 if (encoder->nsc)
374 {
375 nsc_context_free(encoder->nsc);
376 encoder->nsc = nullptr;
377 }
378
379 encoder->codecs &= (UINT32)~FREERDP_CODEC_NSCODEC;
380 return 1;
381}
382
383static int shadow_encoder_uninit_planar(rdpShadowEncoder* encoder)
384{
385 if (encoder->planar)
386 {
387 freerdp_bitmap_planar_context_free(encoder->planar);
388 encoder->planar = nullptr;
389 }
390
391 encoder->codecs &= (UINT32)~FREERDP_CODEC_PLANAR;
392 return 1;
393}
394
395static int shadow_encoder_uninit_interleaved(rdpShadowEncoder* encoder)
396{
397 if (encoder->interleaved)
398 {
399 bitmap_interleaved_context_free(encoder->interleaved);
400 encoder->interleaved = nullptr;
401 }
402
403 encoder->codecs &= (UINT32)~FREERDP_CODEC_INTERLEAVED;
404 return 1;
405}
406
407static int shadow_encoder_uninit_h264(rdpShadowEncoder* encoder)
408{
409 if (encoder->h264)
410 {
411 h264_context_free(encoder->h264);
412 encoder->h264 = nullptr;
413 }
414
415 encoder->codecs &= (UINT32) ~(FREERDP_CODEC_AVC420 | FREERDP_CODEC_AVC444);
416 return 1;
417}
418
419#if defined(WITH_GFX_AV1)
420static int shadow_encoder_uninit_av1(rdpShadowEncoder* encoder)
421{
422 WINPR_ASSERT(encoder);
423
424 freerdp_av1_context_free(encoder->av1);
425 encoder->av1 = nullptr;
426
427 encoder->codecs &= (UINT32) ~(FREERDP_CODEC_AV1_I420 | FREERDP_CODEC_AV1_I444);
428 return 1;
429}
430#endif
431
432static int shadow_encoder_uninit_progressive(rdpShadowEncoder* encoder)
433{
434 WINPR_ASSERT(encoder);
435 if (encoder->progressive)
436 {
437 progressive_context_free(encoder->progressive);
438 encoder->progressive = nullptr;
439 }
440
441 encoder->codecs &= (UINT32)~FREERDP_CODEC_PROGRESSIVE;
442 return 1;
443}
444
445static int shadow_encoder_uninit(rdpShadowEncoder* encoder)
446{
447 shadow_encoder_uninit_grid(encoder);
448
449 if (encoder->bs)
450 {
451 Stream_Free(encoder->bs, TRUE);
452 encoder->bs = nullptr;
453 }
454
455 shadow_encoder_uninit_rfx(encoder);
456
457 shadow_encoder_uninit_nsc(encoder);
458
459 shadow_encoder_uninit_planar(encoder);
460
461 shadow_encoder_uninit_interleaved(encoder);
462 shadow_encoder_uninit_h264(encoder);
463#if defined(WITH_GFX_AV1)
464 shadow_encoder_uninit_av1(encoder);
465#endif
466
467 shadow_encoder_uninit_progressive(encoder);
468
469 return 1;
470}
471
472int shadow_encoder_reset(rdpShadowEncoder* encoder)
473{
474 int status = 0;
475 UINT32 codecs = encoder->codecs;
476 rdpContext* context = (rdpContext*)encoder->client;
477 rdpSettings* settings = context->settings;
478 status = shadow_encoder_uninit(encoder);
479
480 if (status < 0)
481 return -1;
482
483 status = shadow_encoder_init(encoder);
484
485 if (status < 0)
486 return -1;
487
488 status = shadow_encoder_prepare(encoder, codecs);
489
490 if (status < 0)
491 return -1;
492
493 encoder->fps = 16;
494 encoder->maxFps = 32;
495 encoder->frameId = 0;
496 encoder->lastAckframeId = 0;
497 encoder->frameAck = freerdp_settings_get_bool(settings, FreeRDP_SurfaceFrameMarkerEnabled);
498 return 1;
499}
500
501int shadow_encoder_prepare(rdpShadowEncoder* encoder, UINT32 codecs)
502{
503 int status = 0;
504
505 if ((codecs & FREERDP_CODEC_REMOTEFX) && !(encoder->codecs & FREERDP_CODEC_REMOTEFX))
506 {
507 WLog_DBG(TAG, "initializing RemoteFX encoder");
508 status = shadow_encoder_init_rfx(encoder);
509
510 if (status < 0)
511 return -1;
512 }
513
514 if ((codecs & FREERDP_CODEC_NSCODEC) && !(encoder->codecs & FREERDP_CODEC_NSCODEC))
515 {
516 WLog_DBG(TAG, "initializing NSCodec encoder");
517 status = shadow_encoder_init_nsc(encoder);
518
519 if (status < 0)
520 return -1;
521 }
522
523 if ((codecs & FREERDP_CODEC_PLANAR) && !(encoder->codecs & FREERDP_CODEC_PLANAR))
524 {
525 WLog_DBG(TAG, "initializing planar bitmap encoder");
526 status = shadow_encoder_init_planar(encoder);
527
528 if (status < 0)
529 return -1;
530 }
531
532 if ((codecs & FREERDP_CODEC_INTERLEAVED) && !(encoder->codecs & FREERDP_CODEC_INTERLEAVED))
533 {
534 WLog_DBG(TAG, "initializing interleaved bitmap encoder");
535 status = shadow_encoder_init_interleaved(encoder);
536
537 if (status < 0)
538 return -1;
539 }
540
541 if ((codecs & (FREERDP_CODEC_AVC420 | FREERDP_CODEC_AVC444)) &&
542 !(encoder->codecs & (FREERDP_CODEC_AVC420 | FREERDP_CODEC_AVC444)))
543 {
544 WLog_DBG(TAG, "initializing H.264 encoder");
545 status = shadow_encoder_init_h264(encoder);
546
547 if (status < 0)
548 return -1;
549 }
550
551 if ((codecs & FREERDP_CODEC_PROGRESSIVE) && !(encoder->codecs & FREERDP_CODEC_PROGRESSIVE))
552 {
553 WLog_DBG(TAG, "initializing progressive encoder");
554 status = shadow_encoder_init_progressive(encoder);
555
556 if (status < 0)
557 return -1;
558 }
559
560#if defined(WITH_GFX_AV1)
561 const UINT32 cmask = codecs & (FREERDP_CODEC_AV1_I420 | FREERDP_CODEC_AV1_I444);
562 const UINT32 emask = encoder->codecs & (FREERDP_CODEC_AV1_I420 | FREERDP_CODEC_AV1_I444);
563 if (cmask != emask)
564 {
565 WLog_DBG(TAG, "initializing AV1 encoder");
566 status = shadow_encoder_init_av1(encoder, codecs);
567
568 if (status < 0)
569 return -1;
570 }
571#endif
572
573 return 1;
574}
575
576rdpShadowEncoder* shadow_encoder_new(rdpShadowClient* client)
577{
578 rdpShadowEncoder* encoder = nullptr;
579 rdpShadowServer* server = client->server;
580 encoder = (rdpShadowEncoder*)calloc(1, sizeof(rdpShadowEncoder));
581
582 if (!encoder)
583 return nullptr;
584
585 encoder->client = client;
586 encoder->server = server;
587 encoder->fps = 16;
588 encoder->maxFps = 32;
589
590 if (shadow_encoder_init(encoder) < 0)
591 {
592 shadow_encoder_free(encoder);
593 return nullptr;
594 }
595
596 return encoder;
597}
598
599void shadow_encoder_free(rdpShadowEncoder* encoder)
600{
601 if (!encoder)
602 return;
603
604 shadow_encoder_uninit(encoder);
605 free(encoder);
606}
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.