19#include <freerdp/config.h>
21#include <winpr/assert.h>
25#include "shadow_encoder.h"
27#include <freerdp/log.h>
28#define TAG CLIENT_TAG("shadow")
30UINT32 shadow_encoder_preferred_fps(rdpShadowEncoder* encoder)
38UINT32 shadow_encoder_inflight_frames(rdpShadowEncoder* encoder)
47 return (encoder->queueDepth == SUSPEND_FRAME_ACKNOWLEDGEMENT)
49 : encoder->frameId - encoder->lastAckframeId;
52UINT32 shadow_encoder_create_frame_id(rdpShadowEncoder* encoder)
55 UINT32 inFlightFrames = shadow_encoder_inflight_frames(encoder);
62 if (inFlightFrames > 1)
64 encoder->fps = (100 / (inFlightFrames + 1) * encoder->maxFps) / 100;
70 if (encoder->fps > encoder->maxFps)
71 encoder->fps = encoder->maxFps;
77 frameId = ++encoder->frameId;
82static int shadow_encoder_init_grid(rdpShadowEncoder* encoder)
86 encoder->gridWidth = ((encoder->width + (encoder->maxTileWidth - 1)) / encoder->maxTileWidth);
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);
93 if (!encoder->gridBuffer)
96 encoder->grid = (BYTE**)calloc(tileCount,
sizeof(BYTE*));
101 for (UINT32 i = 0; i < encoder->gridHeight; i++)
103 for (UINT32 j = 0; j < encoder->gridWidth; j++)
105 const size_t k = (1ULL * i * encoder->gridWidth) + j;
106 encoder->grid[k] = &(encoder->gridBuffer[k * tileSize]);
113static int shadow_encoder_uninit_grid(rdpShadowEncoder* encoder)
115 if (encoder->gridBuffer)
117 free(encoder->gridBuffer);
118 encoder->gridBuffer =
nullptr;
123 free((
void*)encoder->grid);
124 encoder->grid =
nullptr;
127 encoder->gridWidth = 0;
128 encoder->gridHeight = 0;
133static int shadow_encoder_init_rfx(rdpShadowEncoder* encoder)
136 encoder->rfx = rfx_context_new_ex(
142 if (!rfx_context_reset(encoder->rfx, encoder->width, encoder->height))
148 if (!rfx_context_set_mode(encoder->rfx, WINPR_ASSERTING_INT_CAST(RLGR_MODE, mode)))
151 rfx_context_set_pixel_format(encoder->rfx, PIXEL_FORMAT_BGRX32);
152 encoder->codecs |= FREERDP_CODEC_REMOTEFX;
155 rfx_context_free(encoder->rfx);
156 encoder->rfx =
nullptr;
161static int shadow_encoder_init_nsc(rdpShadowEncoder* encoder)
163 rdpContext* context = (rdpContext*)encoder->client;
164 rdpSettings* settings = context->settings;
167 encoder->nsc = nsc_context_new();
172 if (!nsc_context_reset(encoder->nsc, encoder->width, encoder->height))
175 if (!nsc_context_set_parameters(
176 encoder->nsc, NSC_COLOR_LOSS_LEVEL,
179 if (!nsc_context_set_parameters(
180 encoder->nsc, NSC_ALLOW_SUBSAMPLING,
183 if (!nsc_context_set_parameters(
184 encoder->nsc, NSC_DYNAMIC_COLOR_FIDELITY,
187 if (!nsc_context_set_parameters(encoder->nsc, NSC_COLOR_FORMAT, PIXEL_FORMAT_BGRX32))
189 encoder->codecs |= FREERDP_CODEC_NSCODEC;
192 nsc_context_free(encoder->nsc);
197static int shadow_encoder_init_planar(rdpShadowEncoder* encoder)
199 DWORD planarFlags = 0;
200 rdpContext* context = (rdpContext*)encoder->client;
201 rdpSettings* settings = context->settings;
204 planarFlags |= PLANAR_FORMAT_HEADER_NA;
206 planarFlags |= PLANAR_FORMAT_HEADER_RLE;
208 if (!encoder->planar)
210 encoder->planar = freerdp_bitmap_planar_context_new(planarFlags, encoder->maxTileWidth,
211 encoder->maxTileHeight);
214 if (!encoder->planar)
217 if (!freerdp_bitmap_planar_context_reset(encoder->planar, encoder->maxTileWidth,
218 encoder->maxTileHeight))
221 encoder->codecs |= FREERDP_CODEC_PLANAR;
224 freerdp_bitmap_planar_context_free(encoder->planar);
229static int shadow_encoder_init_interleaved(rdpShadowEncoder* encoder)
231 if (!encoder->interleaved)
232 encoder->interleaved = bitmap_interleaved_context_new(TRUE);
234 if (!encoder->interleaved)
237 if (!bitmap_interleaved_context_reset(encoder->interleaved))
240 encoder->codecs |= FREERDP_CODEC_INTERLEAVED;
243 bitmap_interleaved_context_free(encoder->interleaved);
248static int shadow_encoder_init_h264(rdpShadowEncoder* encoder)
251 encoder->h264 = h264_context_new(TRUE);
256 if (!h264_context_reset(encoder->h264, encoder->width, encoder->height))
259 if (!h264_context_set_option(encoder->h264, H264_CONTEXT_OPTION_RATECONTROL,
260 encoder->server->h264RateControlMode))
262 if (!h264_context_set_option(encoder->h264, H264_CONTEXT_OPTION_BITRATE,
263 encoder->server->h264BitRate))
265 if (!h264_context_set_option(encoder->h264, H264_CONTEXT_OPTION_FRAMERATE,
266 encoder->server->h264FrameRate))
268 if (!h264_context_set_option(encoder->h264, H264_CONTEXT_OPTION_QP, encoder->server->h264QP))
270 if (!h264_context_set_option(encoder->h264, H264_CONTEXT_OPTION_HW_ACCEL,
271 (UINT32)encoder->server->h264HwAccel))
274 encoder->codecs |= FREERDP_CODEC_AVC420 | FREERDP_CODEC_AVC444;
277 h264_context_free(encoder->h264);
281#if defined(WITH_GFX_AV1)
283static int shadow_encoder_init_av1(rdpShadowEncoder* encoder, UINT32 codecs)
285 WINPR_ASSERT(encoder);
288 if ((codecs & FREERDP_CODEC_AV1_I444) != 0)
292 encoder->av1 = freerdp_av1_context_new(TRUE);
297 if (!freerdp_av1_context_reset(encoder->av1, encoder->width, encoder->height))
300 if (!freerdp_av1_context_set_option(encoder->av1, FREERDP_AV1_CONTEXT_OPTION_PROFILE, profile))
303 if (!freerdp_av1_context_set_option(encoder->av1, FREERDP_AV1_CONTEXT_OPTION_RATECONTROL,
304 encoder->server->AV1RateControlMode))
306 if (!freerdp_av1_context_set_option(encoder->av1, FREERDP_AV1_CONTEXT_OPTION_BITRATE,
307 encoder->server->AV1BitRate))
310 encoder->codecs &= ~(FREERDP_CODEC_AV1_I420 | FREERDP_CODEC_AV1_I444);
311 encoder->codecs |= codecs;
314 freerdp_av1_context_free(encoder->av1);
315 encoder->av1 =
nullptr;
321static int shadow_encoder_init_progressive(rdpShadowEncoder* encoder)
323 WINPR_ASSERT(encoder);
324 if (!encoder->progressive)
325 encoder->progressive = progressive_context_new(TRUE);
327 if (!encoder->progressive)
330 if (!progressive_context_reset(encoder->progressive))
333 encoder->codecs |= FREERDP_CODEC_PROGRESSIVE;
336 progressive_context_free(encoder->progressive);
341static int shadow_encoder_init(rdpShadowEncoder* encoder)
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)
351 encoder->bs = Stream_New(
nullptr, 4ULL * encoder->maxTileWidth * encoder->maxTileHeight);
359static int shadow_encoder_uninit_rfx(rdpShadowEncoder* encoder)
363 rfx_context_free(encoder->rfx);
364 encoder->rfx =
nullptr;
367 encoder->codecs &= (UINT32)~FREERDP_CODEC_REMOTEFX;
371static int shadow_encoder_uninit_nsc(rdpShadowEncoder* encoder)
375 nsc_context_free(encoder->nsc);
376 encoder->nsc =
nullptr;
379 encoder->codecs &= (UINT32)~FREERDP_CODEC_NSCODEC;
383static int shadow_encoder_uninit_planar(rdpShadowEncoder* encoder)
387 freerdp_bitmap_planar_context_free(encoder->planar);
388 encoder->planar =
nullptr;
391 encoder->codecs &= (UINT32)~FREERDP_CODEC_PLANAR;
395static int shadow_encoder_uninit_interleaved(rdpShadowEncoder* encoder)
397 if (encoder->interleaved)
399 bitmap_interleaved_context_free(encoder->interleaved);
400 encoder->interleaved =
nullptr;
403 encoder->codecs &= (UINT32)~FREERDP_CODEC_INTERLEAVED;
407static int shadow_encoder_uninit_h264(rdpShadowEncoder* encoder)
411 h264_context_free(encoder->h264);
412 encoder->h264 =
nullptr;
415 encoder->codecs &= (UINT32) ~(FREERDP_CODEC_AVC420 | FREERDP_CODEC_AVC444);
419#if defined(WITH_GFX_AV1)
420static int shadow_encoder_uninit_av1(rdpShadowEncoder* encoder)
422 WINPR_ASSERT(encoder);
424 freerdp_av1_context_free(encoder->av1);
425 encoder->av1 =
nullptr;
427 encoder->codecs &= (UINT32) ~(FREERDP_CODEC_AV1_I420 | FREERDP_CODEC_AV1_I444);
432static int shadow_encoder_uninit_progressive(rdpShadowEncoder* encoder)
434 WINPR_ASSERT(encoder);
435 if (encoder->progressive)
437 progressive_context_free(encoder->progressive);
438 encoder->progressive =
nullptr;
441 encoder->codecs &= (UINT32)~FREERDP_CODEC_PROGRESSIVE;
445static int shadow_encoder_uninit(rdpShadowEncoder* encoder)
447 shadow_encoder_uninit_grid(encoder);
451 Stream_Free(encoder->bs, TRUE);
452 encoder->bs =
nullptr;
455 shadow_encoder_uninit_rfx(encoder);
457 shadow_encoder_uninit_nsc(encoder);
459 shadow_encoder_uninit_planar(encoder);
461 shadow_encoder_uninit_interleaved(encoder);
462 shadow_encoder_uninit_h264(encoder);
463#if defined(WITH_GFX_AV1)
464 shadow_encoder_uninit_av1(encoder);
467 shadow_encoder_uninit_progressive(encoder);
472int shadow_encoder_reset(rdpShadowEncoder* encoder)
475 UINT32 codecs = encoder->codecs;
476 rdpContext* context = (rdpContext*)encoder->client;
477 rdpSettings* settings = context->settings;
478 status = shadow_encoder_uninit(encoder);
483 status = shadow_encoder_init(encoder);
488 status = shadow_encoder_prepare(encoder, codecs);
494 encoder->maxFps = 32;
495 encoder->frameId = 0;
496 encoder->lastAckframeId = 0;
501int shadow_encoder_prepare(rdpShadowEncoder* encoder, UINT32 codecs)
505 if ((codecs & FREERDP_CODEC_REMOTEFX) && !(encoder->codecs & FREERDP_CODEC_REMOTEFX))
507 WLog_DBG(TAG,
"initializing RemoteFX encoder");
508 status = shadow_encoder_init_rfx(encoder);
514 if ((codecs & FREERDP_CODEC_NSCODEC) && !(encoder->codecs & FREERDP_CODEC_NSCODEC))
516 WLog_DBG(TAG,
"initializing NSCodec encoder");
517 status = shadow_encoder_init_nsc(encoder);
523 if ((codecs & FREERDP_CODEC_PLANAR) && !(encoder->codecs & FREERDP_CODEC_PLANAR))
525 WLog_DBG(TAG,
"initializing planar bitmap encoder");
526 status = shadow_encoder_init_planar(encoder);
532 if ((codecs & FREERDP_CODEC_INTERLEAVED) && !(encoder->codecs & FREERDP_CODEC_INTERLEAVED))
534 WLog_DBG(TAG,
"initializing interleaved bitmap encoder");
535 status = shadow_encoder_init_interleaved(encoder);
541 if ((codecs & (FREERDP_CODEC_AVC420 | FREERDP_CODEC_AVC444)) &&
542 !(encoder->codecs & (FREERDP_CODEC_AVC420 | FREERDP_CODEC_AVC444)))
544 WLog_DBG(TAG,
"initializing H.264 encoder");
545 status = shadow_encoder_init_h264(encoder);
551 if ((codecs & FREERDP_CODEC_PROGRESSIVE) && !(encoder->codecs & FREERDP_CODEC_PROGRESSIVE))
553 WLog_DBG(TAG,
"initializing progressive encoder");
554 status = shadow_encoder_init_progressive(encoder);
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);
565 WLog_DBG(TAG,
"initializing AV1 encoder");
566 status = shadow_encoder_init_av1(encoder, codecs);
576rdpShadowEncoder* shadow_encoder_new(rdpShadowClient* client)
578 rdpShadowEncoder* encoder =
nullptr;
579 rdpShadowServer* server = client->server;
580 encoder = (rdpShadowEncoder*)calloc(1,
sizeof(rdpShadowEncoder));
585 encoder->client = client;
586 encoder->server = server;
588 encoder->maxFps = 32;
590 if (shadow_encoder_init(encoder) < 0)
592 shadow_encoder_free(encoder);
599void shadow_encoder_free(rdpShadowEncoder* encoder)
604 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.