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
277#if defined(WITH_GFX_AV1)
278WINPR_ATTR_NODISCARD
279static int shadow_encoder_init_av1(rdpShadowEncoder* encoder, UINT32 codecs)
280{
281 WINPR_ASSERT(encoder);
282
283 UINT32 profile = 0;
284 if ((codecs & FREERDP_CODEC_AV1_I444) != 0)
285 profile = 1;
286
287 if (!encoder->av1)
288 encoder->av1 = freerdp_av1_context_new(TRUE);
289
290 if (!encoder->av1)
291 goto fail;
292
293 if (!freerdp_av1_context_reset(encoder->av1, encoder->width, encoder->height))
294 goto fail;
295
296 if (!freerdp_av1_context_set_option(encoder->av1, FREERDP_AV1_CONTEXT_OPTION_PROFILE, profile))
297 goto fail;
298
299 if (!freerdp_av1_context_set_option(encoder->av1, FREERDP_AV1_CONTEXT_OPTION_RATECONTROL,
300 encoder->server->AV1RateControlMode))
301 goto fail;
302 if (!freerdp_av1_context_set_option(encoder->av1, FREERDP_AV1_CONTEXT_OPTION_BITRATE,
303 encoder->server->AV1BitRate))
304 goto fail;
305
306 encoder->codecs &= ~(FREERDP_CODEC_AV1_I420 | FREERDP_CODEC_AV1_I444);
307 encoder->codecs |= codecs;
308 return 1;
309fail:
310 freerdp_av1_context_free(encoder->av1);
311 encoder->av1 = nullptr;
312 return -1;
313}
314#endif
315
316WINPR_ATTR_NODISCARD
317static int shadow_encoder_init_progressive(rdpShadowEncoder* encoder)
318{
319 WINPR_ASSERT(encoder);
320 if (!encoder->progressive)
321 encoder->progressive = progressive_context_new(TRUE);
322
323 if (!encoder->progressive)
324 goto fail;
325
326 if (!progressive_context_reset(encoder->progressive))
327 goto fail;
328
329 encoder->codecs |= FREERDP_CODEC_PROGRESSIVE;
330 return 1;
331fail:
332 progressive_context_free(encoder->progressive);
333 return -1;
334}
335
336WINPR_ATTR_NODISCARD
337static int shadow_encoder_init(rdpShadowEncoder* encoder)
338{
339 encoder->width = encoder->server->screen->width;
340 encoder->height = encoder->server->screen->height;
341 encoder->maxTileWidth = 64;
342 encoder->maxTileHeight = 64;
343 if (shadow_encoder_init_grid(encoder) < 0)
344 return -1;
345
346 if (!encoder->bs)
347 encoder->bs = Stream_New(nullptr, 4ULL * encoder->maxTileWidth * encoder->maxTileHeight);
348
349 if (!encoder->bs)
350 return -1;
351
352 return 1;
353}
354
355static int shadow_encoder_uninit_rfx(rdpShadowEncoder* encoder)
356{
357 if (encoder->rfx)
358 {
359 rfx_context_free(encoder->rfx);
360 encoder->rfx = nullptr;
361 }
362
363 encoder->codecs &= (UINT32)~FREERDP_CODEC_REMOTEFX;
364 return 1;
365}
366
367static int shadow_encoder_uninit_nsc(rdpShadowEncoder* encoder)
368{
369 if (encoder->nsc)
370 {
371 nsc_context_free(encoder->nsc);
372 encoder->nsc = nullptr;
373 }
374
375 encoder->codecs &= (UINT32)~FREERDP_CODEC_NSCODEC;
376 return 1;
377}
378
379static int shadow_encoder_uninit_planar(rdpShadowEncoder* encoder)
380{
381 if (encoder->planar)
382 {
383 freerdp_bitmap_planar_context_free(encoder->planar);
384 encoder->planar = nullptr;
385 }
386
387 encoder->codecs &= (UINT32)~FREERDP_CODEC_PLANAR;
388 return 1;
389}
390
391static int shadow_encoder_uninit_interleaved(rdpShadowEncoder* encoder)
392{
393 if (encoder->interleaved)
394 {
395 bitmap_interleaved_context_free(encoder->interleaved);
396 encoder->interleaved = nullptr;
397 }
398
399 encoder->codecs &= (UINT32)~FREERDP_CODEC_INTERLEAVED;
400 return 1;
401}
402
403static int shadow_encoder_uninit_h264(rdpShadowEncoder* encoder)
404{
405 if (encoder->h264)
406 {
407 h264_context_free(encoder->h264);
408 encoder->h264 = nullptr;
409 }
410
411 encoder->codecs &= (UINT32) ~(FREERDP_CODEC_AVC420 | FREERDP_CODEC_AVC444);
412 return 1;
413}
414
415#if defined(WITH_GFX_AV1)
416static int shadow_encoder_uninit_av1(rdpShadowEncoder* encoder)
417{
418 WINPR_ASSERT(encoder);
419
420 freerdp_av1_context_free(encoder->av1);
421 encoder->av1 = nullptr;
422
423 encoder->codecs &= (UINT32) ~(FREERDP_CODEC_AV1_I420 | FREERDP_CODEC_AV1_I444);
424 return 1;
425}
426#endif
427
428static int shadow_encoder_uninit_progressive(rdpShadowEncoder* encoder)
429{
430 WINPR_ASSERT(encoder);
431 if (encoder->progressive)
432 {
433 progressive_context_free(encoder->progressive);
434 encoder->progressive = nullptr;
435 }
436
437 encoder->codecs &= (UINT32)~FREERDP_CODEC_PROGRESSIVE;
438 return 1;
439}
440
441static int shadow_encoder_uninit(rdpShadowEncoder* encoder)
442{
443 shadow_encoder_uninit_grid(encoder);
444
445 if (encoder->bs)
446 {
447 Stream_Free(encoder->bs, TRUE);
448 encoder->bs = nullptr;
449 }
450
451 shadow_encoder_uninit_rfx(encoder);
452
453 shadow_encoder_uninit_nsc(encoder);
454
455 shadow_encoder_uninit_planar(encoder);
456
457 shadow_encoder_uninit_interleaved(encoder);
458 shadow_encoder_uninit_h264(encoder);
459#if defined(WITH_GFX_AV1)
460 shadow_encoder_uninit_av1(encoder);
461#endif
462
463 shadow_encoder_uninit_progressive(encoder);
464
465 return 1;
466}
467
468int shadow_encoder_reset(rdpShadowEncoder* encoder)
469{
470 int status = 0;
471 UINT32 codecs = encoder->codecs;
472 rdpContext* context = (rdpContext*)encoder->client;
473 rdpSettings* settings = context->settings;
474 status = shadow_encoder_uninit(encoder);
475
476 if (status < 0)
477 return -1;
478
479 status = shadow_encoder_init(encoder);
480
481 if (status < 0)
482 return -1;
483
484 status = shadow_encoder_prepare(encoder, codecs);
485
486 if (status < 0)
487 return -1;
488
489 encoder->fps = 16;
490 encoder->maxFps = 32;
491 encoder->frameId = 0;
492 encoder->lastAckframeId = 0;
493 encoder->frameAck = freerdp_settings_get_bool(settings, FreeRDP_SurfaceFrameMarkerEnabled);
494 return 1;
495}
496
497int shadow_encoder_prepare(rdpShadowEncoder* encoder, UINT32 codecs)
498{
499 int status = 0;
500
501 if ((codecs & FREERDP_CODEC_REMOTEFX) && !(encoder->codecs & FREERDP_CODEC_REMOTEFX))
502 {
503 WLog_DBG(TAG, "initializing RemoteFX encoder");
504 status = shadow_encoder_init_rfx(encoder);
505
506 if (status < 0)
507 return -1;
508 }
509
510 if ((codecs & FREERDP_CODEC_NSCODEC) && !(encoder->codecs & FREERDP_CODEC_NSCODEC))
511 {
512 WLog_DBG(TAG, "initializing NSCodec encoder");
513 status = shadow_encoder_init_nsc(encoder);
514
515 if (status < 0)
516 return -1;
517 }
518
519 if ((codecs & FREERDP_CODEC_PLANAR) && !(encoder->codecs & FREERDP_CODEC_PLANAR))
520 {
521 WLog_DBG(TAG, "initializing planar bitmap encoder");
522 status = shadow_encoder_init_planar(encoder);
523
524 if (status < 0)
525 return -1;
526 }
527
528 if ((codecs & FREERDP_CODEC_INTERLEAVED) && !(encoder->codecs & FREERDP_CODEC_INTERLEAVED))
529 {
530 WLog_DBG(TAG, "initializing interleaved bitmap encoder");
531 status = shadow_encoder_init_interleaved(encoder);
532
533 if (status < 0)
534 return -1;
535 }
536
537 if ((codecs & (FREERDP_CODEC_AVC420 | FREERDP_CODEC_AVC444)) &&
538 !(encoder->codecs & (FREERDP_CODEC_AVC420 | FREERDP_CODEC_AVC444)))
539 {
540 WLog_DBG(TAG, "initializing H.264 encoder");
541 status = shadow_encoder_init_h264(encoder);
542
543 if (status < 0)
544 return -1;
545 }
546
547 if ((codecs & FREERDP_CODEC_PROGRESSIVE) && !(encoder->codecs & FREERDP_CODEC_PROGRESSIVE))
548 {
549 WLog_DBG(TAG, "initializing progressive encoder");
550 status = shadow_encoder_init_progressive(encoder);
551
552 if (status < 0)
553 return -1;
554 }
555
556#if defined(WITH_GFX_AV1)
557 const UINT32 cmask = codecs & (FREERDP_CODEC_AV1_I420 | FREERDP_CODEC_AV1_I444);
558 const UINT32 emask = encoder->codecs & (FREERDP_CODEC_AV1_I420 | FREERDP_CODEC_AV1_I444);
559 if (cmask != emask)
560 {
561 WLog_DBG(TAG, "initializing AV1 encoder");
562 status = shadow_encoder_init_av1(encoder, codecs);
563
564 if (status < 0)
565 return -1;
566 }
567#endif
568
569 return 1;
570}
571
572rdpShadowEncoder* shadow_encoder_new(rdpShadowClient* client)
573{
574 rdpShadowEncoder* encoder = nullptr;
575 rdpShadowServer* server = client->server;
576 encoder = (rdpShadowEncoder*)calloc(1, sizeof(rdpShadowEncoder));
577
578 if (!encoder)
579 return nullptr;
580
581 encoder->client = client;
582 encoder->server = server;
583 encoder->fps = 16;
584 encoder->maxFps = 32;
585
586 if (shadow_encoder_init(encoder) < 0)
587 {
588 shadow_encoder_free(encoder);
589 return nullptr;
590 }
591
592 return encoder;
593}
594
595void shadow_encoder_free(rdpShadowEncoder* encoder)
596{
597 if (!encoder)
598 return;
599
600 shadow_encoder_uninit(encoder);
601 free(encoder);
602}
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.