19#include <freerdp/config.h>
24#include <winpr/assert.h>
25#include <winpr/sysinfo.h>
29#include "shadow_encoder.h"
31#include <freerdp/log.h>
32#define TAG CLIENT_TAG("shadow")
34UINT32 shadow_encoder_preferred_fps(rdpShadowEncoder* encoder)
42UINT32 shadow_encoder_inflight_frames(rdpShadowEncoder* encoder)
51 if (encoder->queueDepth == SUSPEND_FRAME_ACKNOWLEDGEMENT)
53 if (encoder->lastAckframeId > encoder->frameId)
55 return encoder->frameId - encoder->lastAckframeId;
58UINT32 shadow_encoder_create_frame_id(rdpShadowEncoder* encoder)
60 const UINT64 inFlightFrames = shadow_encoder_inflight_frames(encoder);
67 if (inFlightFrames > 1)
69 UINT64 fps = (100 / (inFlightFrames + 1) * encoder->maxFps) / 100;
70 if (fps > encoder->maxFps)
71 fps = encoder->maxFps;
72 encoder->fps = WINPR_ASSERTING_INT_CAST(UINT32, fps);
78 if (encoder->fps > encoder->maxFps)
79 encoder->fps = encoder->maxFps;
85 const UINT32 frameId = ++encoder->frameId;
90static int shadow_encoder_init_grid(rdpShadowEncoder* encoder)
94 encoder->gridWidth = ((encoder->width + (encoder->maxTileWidth - 1)) / encoder->maxTileWidth);
96 ((encoder->height + (encoder->maxTileHeight - 1)) / encoder->maxTileHeight);
97 tileSize = encoder->maxTileWidth * encoder->maxTileHeight * 4;
98 tileCount = encoder->gridWidth * encoder->gridHeight;
99 encoder->gridBuffer = (BYTE*)calloc(tileSize, tileCount);
101 if (!encoder->gridBuffer)
104 encoder->grid = (BYTE**)calloc(tileCount,
sizeof(BYTE*));
109 for (UINT32 i = 0; i < encoder->gridHeight; i++)
111 for (UINT32 j = 0; j < encoder->gridWidth; j++)
113 const size_t k = (1ULL * i * encoder->gridWidth) + j;
114 encoder->grid[k] = &(encoder->gridBuffer[k * tileSize]);
121static int shadow_encoder_uninit_grid(rdpShadowEncoder* encoder)
123 if (encoder->gridBuffer)
125 free(encoder->gridBuffer);
126 encoder->gridBuffer =
nullptr;
131 free((
void*)encoder->grid);
132 encoder->grid =
nullptr;
135 encoder->gridWidth = 0;
136 encoder->gridHeight = 0;
141static int shadow_encoder_init_rfx(rdpShadowEncoder* encoder)
144 encoder->rfx = rfx_context_new_ex(
150 if (!rfx_context_reset(encoder->rfx, encoder->width, encoder->height))
156 if (!rfx_context_set_mode(encoder->rfx, WINPR_ASSERTING_INT_CAST(RLGR_MODE, mode)))
159 rfx_context_set_pixel_format(encoder->rfx, PIXEL_FORMAT_BGRX32);
160 encoder->codecs |= FREERDP_CODEC_REMOTEFX;
163 rfx_context_free(encoder->rfx);
164 encoder->rfx =
nullptr;
169static int shadow_encoder_init_nsc(rdpShadowEncoder* encoder)
171 rdpContext* context = (rdpContext*)encoder->client;
172 rdpSettings* settings = context->settings;
175 encoder->nsc = nsc_context_new();
180 if (!nsc_context_reset(encoder->nsc, encoder->width, encoder->height))
183 if (!nsc_context_set_parameters(
184 encoder->nsc, NSC_COLOR_LOSS_LEVEL,
187 if (!nsc_context_set_parameters(
188 encoder->nsc, NSC_ALLOW_SUBSAMPLING,
191 if (!nsc_context_set_parameters(
192 encoder->nsc, NSC_DYNAMIC_COLOR_FIDELITY,
195 if (!nsc_context_set_parameters(encoder->nsc, NSC_COLOR_FORMAT, PIXEL_FORMAT_BGRX32))
197 encoder->codecs |= FREERDP_CODEC_NSCODEC;
200 nsc_context_free(encoder->nsc);
205static int shadow_encoder_init_planar(rdpShadowEncoder* encoder)
207 DWORD planarFlags = 0;
208 rdpContext* context = (rdpContext*)encoder->client;
209 rdpSettings* settings = context->settings;
212 planarFlags |= PLANAR_FORMAT_HEADER_NA;
214 planarFlags |= PLANAR_FORMAT_HEADER_RLE;
216 if (!encoder->planar)
218 encoder->planar = freerdp_bitmap_planar_context_new(planarFlags, encoder->maxTileWidth,
219 encoder->maxTileHeight);
222 if (!encoder->planar)
225 if (!freerdp_bitmap_planar_context_reset(encoder->planar, encoder->maxTileWidth,
226 encoder->maxTileHeight))
229 encoder->codecs |= FREERDP_CODEC_PLANAR;
232 freerdp_bitmap_planar_context_free(encoder->planar);
237static int shadow_encoder_init_interleaved(rdpShadowEncoder* encoder)
239 if (!encoder->interleaved)
240 encoder->interleaved = bitmap_interleaved_context_new(TRUE);
242 if (!encoder->interleaved)
245 if (!bitmap_interleaved_context_reset(encoder->interleaved))
248 encoder->codecs |= FREERDP_CODEC_INTERLEAVED;
251 bitmap_interleaved_context_free(encoder->interleaved);
256static int shadow_encoder_init_h264(rdpShadowEncoder* encoder)
259 encoder->h264 = h264_context_new(TRUE);
264 if (!h264_context_reset(encoder->h264, encoder->width, encoder->height))
267 if (!h264_context_set_option(encoder->h264, H264_CONTEXT_OPTION_RATECONTROL,
268 encoder->server->h264RateControlMode))
270 if (!h264_context_set_option(encoder->h264, H264_CONTEXT_OPTION_BITRATE,
271 encoder->server->h264BitRate))
273 if (!h264_context_set_option(encoder->h264, H264_CONTEXT_OPTION_FRAMERATE,
274 encoder->server->h264FrameRate))
276 if (!h264_context_set_option(encoder->h264, H264_CONTEXT_OPTION_QP, encoder->server->h264QP))
278 if (!h264_context_set_option(encoder->h264, H264_CONTEXT_OPTION_HW_ACCEL,
279 (UINT32)encoder->server->h264HwAccel))
282 encoder->codecs |= FREERDP_CODEC_AVC420 | FREERDP_CODEC_AVC444;
285 h264_context_free(encoder->h264);
289#if defined(WITH_GFX_AV1)
291static int shadow_encoder_init_av1(rdpShadowEncoder* encoder, UINT32 codecs)
293 WINPR_ASSERT(encoder);
296 if ((codecs & FREERDP_CODEC_AV1_I444) != 0)
300 encoder->av1 = freerdp_av1_context_new(TRUE);
305 if (!freerdp_av1_context_reset(encoder->av1, encoder->width, encoder->height))
308 if (!freerdp_av1_context_set_option(encoder->av1, FREERDP_AV1_CONTEXT_OPTION_PROFILE, profile))
311 if (!freerdp_av1_context_set_option(encoder->av1, FREERDP_AV1_CONTEXT_OPTION_RATECONTROL,
312 encoder->server->AV1RateControlMode))
314 if (!freerdp_av1_context_set_option(encoder->av1, FREERDP_AV1_CONTEXT_OPTION_BITRATE,
315 encoder->server->AV1BitRate))
318 encoder->codecs &= ~(FREERDP_CODEC_AV1_I420 | FREERDP_CODEC_AV1_I444);
319 encoder->codecs |= codecs & (FREERDP_CODEC_AV1_I420 | FREERDP_CODEC_AV1_I444);
322 freerdp_av1_context_free(encoder->av1);
323 encoder->av1 =
nullptr;
328#if defined(WITH_GFX_AV2)
330static int shadow_encoder_init_av2(rdpShadowEncoder* encoder, UINT32 codecs)
332 WINPR_ASSERT(encoder);
335 if ((codecs & FREERDP_CODEC_AV2_I444) != 0)
339 encoder->av2 = freerdp_av2_context_new(TRUE);
344 if (!freerdp_av2_context_reset(encoder->av2, encoder->width, encoder->height))
347 if (!freerdp_av2_context_set_option(encoder->av2, FREERDP_AV2_CONTEXT_OPTION_PROFILE, profile))
350 if (!freerdp_av2_context_set_option(encoder->av2, FREERDP_AV2_CONTEXT_OPTION_RATECONTROL,
351 encoder->server->AV2RateControlMode))
353 if (!freerdp_av2_context_set_option(encoder->av2, FREERDP_AV2_CONTEXT_OPTION_BITRATE,
354 encoder->server->AV2BitRate))
357 encoder->codecs &= ~(FREERDP_CODEC_AV2_I420 | FREERDP_CODEC_AV2_I444);
358 encoder->codecs |= codecs & (FREERDP_CODEC_AV2_I420 | FREERDP_CODEC_AV2_I444);
361 freerdp_av2_context_free(encoder->av2);
362 encoder->av2 =
nullptr;
368static int shadow_encoder_init_progressive(rdpShadowEncoder* encoder)
370 WINPR_ASSERT(encoder);
371 if (!encoder->progressive)
372 encoder->progressive = progressive_context_new(TRUE);
374 if (!encoder->progressive)
377 if (!progressive_context_reset(encoder->progressive))
380 encoder->codecs |= FREERDP_CODEC_PROGRESSIVE;
383 progressive_context_free(encoder->progressive);
388static int shadow_encoder_init(rdpShadowEncoder* encoder)
390 encoder->width = encoder->server->screen->width;
391 encoder->height = encoder->server->screen->height;
392 encoder->maxTileWidth = 64;
393 encoder->maxTileHeight = 64;
394 if (shadow_encoder_init_grid(encoder) < 0)
398 encoder->bs = Stream_New(
nullptr, 4ULL * encoder->maxTileWidth * encoder->maxTileHeight);
406static int shadow_encoder_uninit_rfx(rdpShadowEncoder* encoder)
410 rfx_context_free(encoder->rfx);
411 encoder->rfx =
nullptr;
414 encoder->codecs &= (UINT32)~FREERDP_CODEC_REMOTEFX;
418static int shadow_encoder_uninit_nsc(rdpShadowEncoder* encoder)
422 nsc_context_free(encoder->nsc);
423 encoder->nsc =
nullptr;
426 encoder->codecs &= (UINT32)~FREERDP_CODEC_NSCODEC;
430static int shadow_encoder_uninit_planar(rdpShadowEncoder* encoder)
434 freerdp_bitmap_planar_context_free(encoder->planar);
435 encoder->planar =
nullptr;
438 encoder->codecs &= (UINT32)~FREERDP_CODEC_PLANAR;
442static int shadow_encoder_uninit_interleaved(rdpShadowEncoder* encoder)
444 if (encoder->interleaved)
446 bitmap_interleaved_context_free(encoder->interleaved);
447 encoder->interleaved =
nullptr;
450 encoder->codecs &= (UINT32)~FREERDP_CODEC_INTERLEAVED;
454static int shadow_encoder_uninit_h264(rdpShadowEncoder* encoder)
458 h264_context_free(encoder->h264);
459 encoder->h264 =
nullptr;
462 encoder->codecs &= (UINT32) ~(FREERDP_CODEC_AVC420 | FREERDP_CODEC_AVC444);
466#if defined(WITH_GFX_AV1)
467static int shadow_encoder_uninit_av1(rdpShadowEncoder* encoder)
469 WINPR_ASSERT(encoder);
471 freerdp_av1_context_free(encoder->av1);
472 encoder->av1 =
nullptr;
474 encoder->codecs &= (UINT32) ~(FREERDP_CODEC_AV1_I420 | FREERDP_CODEC_AV1_I444);
479#if defined(WITH_GFX_AV2)
480static int shadow_encoder_uninit_av2(rdpShadowEncoder* encoder)
482 WINPR_ASSERT(encoder);
484 freerdp_av2_context_free(encoder->av2);
485 encoder->av2 =
nullptr;
487 encoder->codecs &= (UINT32) ~(FREERDP_CODEC_AV2_I420 | FREERDP_CODEC_AV2_I444);
492static int shadow_encoder_uninit_progressive(rdpShadowEncoder* encoder)
494 WINPR_ASSERT(encoder);
495 if (encoder->progressive)
497 progressive_context_free(encoder->progressive);
498 encoder->progressive =
nullptr;
501 encoder->codecs &= (UINT32)~FREERDP_CODEC_PROGRESSIVE;
505static int shadow_encoder_uninit(rdpShadowEncoder* encoder)
507 shadow_encoder_uninit_grid(encoder);
511 Stream_Free(encoder->bs, TRUE);
512 encoder->bs =
nullptr;
515 shadow_encoder_uninit_rfx(encoder);
517 shadow_encoder_uninit_nsc(encoder);
519 shadow_encoder_uninit_planar(encoder);
521 shadow_encoder_uninit_interleaved(encoder);
522 shadow_encoder_uninit_h264(encoder);
523#if defined(WITH_GFX_AV1)
524 shadow_encoder_uninit_av1(encoder);
526#if defined(WITH_GFX_AV2)
527 shadow_encoder_uninit_av2(encoder);
530 shadow_encoder_uninit_progressive(encoder);
535 free(encoder->gfxSnapshot);
536 encoder->gfxSnapshot =
nullptr;
537 free(encoder->gfxTileEncoded);
538 encoder->gfxTileEncoded =
nullptr;
539 encoder->gfxSnapshotValid = FALSE;
540 encoder->gfxSnapshotWidth = 0;
541 encoder->gfxSnapshotHeight = 0;
542 encoder->gfxSnapshotStep = 0;
547int shadow_encoder_reset(rdpShadowEncoder* encoder)
550 UINT32 codecs = encoder->codecs;
551 rdpContext* context = (rdpContext*)encoder->client;
552 rdpSettings* settings = context->settings;
553 status = shadow_encoder_uninit(encoder);
558 status = shadow_encoder_init(encoder);
563 status = shadow_encoder_prepare(encoder, codecs);
569 encoder->maxFps = 32;
570 encoder->frameId = 0;
571 encoder->lastAckframeId = 0;
572 encoder->lastAckTick = GetTickCount64();
573 encoder->gfxHeld = FALSE;
578int shadow_encoder_prepare(rdpShadowEncoder* encoder, UINT32 codecs)
582 if ((codecs & FREERDP_CODEC_REMOTEFX) && !(encoder->codecs & FREERDP_CODEC_REMOTEFX))
584 WLog_DBG(TAG,
"initializing RemoteFX encoder");
585 status = shadow_encoder_init_rfx(encoder);
591 if ((codecs & FREERDP_CODEC_NSCODEC) && !(encoder->codecs & FREERDP_CODEC_NSCODEC))
593 WLog_DBG(TAG,
"initializing NSCodec encoder");
594 status = shadow_encoder_init_nsc(encoder);
600 if ((codecs & FREERDP_CODEC_PLANAR) && !(encoder->codecs & FREERDP_CODEC_PLANAR))
602 WLog_DBG(TAG,
"initializing planar bitmap encoder");
603 status = shadow_encoder_init_planar(encoder);
609 if ((codecs & FREERDP_CODEC_INTERLEAVED) && !(encoder->codecs & FREERDP_CODEC_INTERLEAVED))
611 WLog_DBG(TAG,
"initializing interleaved bitmap encoder");
612 status = shadow_encoder_init_interleaved(encoder);
618 if ((codecs & (FREERDP_CODEC_AVC420 | FREERDP_CODEC_AVC444)) &&
619 !(encoder->codecs & (FREERDP_CODEC_AVC420 | FREERDP_CODEC_AVC444)))
621 WLog_DBG(TAG,
"initializing H.264 encoder");
622 status = shadow_encoder_init_h264(encoder);
628 if ((codecs & FREERDP_CODEC_PROGRESSIVE) && !(encoder->codecs & FREERDP_CODEC_PROGRESSIVE))
630 WLog_DBG(TAG,
"initializing progressive encoder");
631 status = shadow_encoder_init_progressive(encoder);
637#if defined(WITH_GFX_AV1)
638 const UINT32 cmask = codecs & (FREERDP_CODEC_AV1_I420 | FREERDP_CODEC_AV1_I444);
639 const UINT32 emask = encoder->codecs & (FREERDP_CODEC_AV1_I420 | FREERDP_CODEC_AV1_I444);
641 if ((cmask != 0) && (cmask != emask))
643 WLog_DBG(TAG,
"initializing AV1 encoder");
644 status = shadow_encoder_init_av1(encoder, codecs);
651#if defined(WITH_GFX_AV2)
652 const UINT32 cmask2 = codecs & (FREERDP_CODEC_AV2_I420 | FREERDP_CODEC_AV2_I444);
653 const UINT32 emask2 = encoder->codecs & (FREERDP_CODEC_AV2_I420 | FREERDP_CODEC_AV2_I444);
654 if ((cmask2 != 0) && (cmask2 != emask2))
656 WLog_DBG(TAG,
"initializing AV2 encoder");
657 status = shadow_encoder_init_av2(encoder, codecs);
667rdpShadowEncoder* shadow_encoder_new(rdpShadowClient* client)
669 rdpShadowEncoder* encoder =
nullptr;
670 rdpShadowServer* server = client->server;
671 encoder = (rdpShadowEncoder*)calloc(1,
sizeof(rdpShadowEncoder));
676 encoder->client = client;
677 encoder->server = server;
679 encoder->maxFps = 32;
680 encoder->lastAckTick = GetTickCount64();
684 const char* env = getenv(
"FREERDP_SHADOW_GFX_FRAMES_IN_FLIGHT");
685 encoder->maxInFlight = SHADOW_GFX_FRAMES_IN_FLIGHT;
690 const unsigned long value = strtoul(env, &end, 10);
691 if ((errno == 0) && end && (*end ==
'\0') && (value <= 1000))
692 encoder->maxInFlight = (UINT32)value;
694 WLog_WARN(TAG,
"FREERDP_SHADOW_GFX_FRAMES_IN_FLIGHT=%s ignored: 0 to 1000", env);
698 if (shadow_encoder_init(encoder) < 0)
700 shadow_encoder_free(encoder);
707void shadow_encoder_free(rdpShadowEncoder* encoder)
712 shadow_encoder_uninit(encoder);
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.