FreeRDP/server/shadow/shadow_encoder.c

483 lines
11 KiB
C
Raw Normal View History

2014-07-12 04:49:56 +04:00
/**
* FreeRDP: A Remote Desktop Protocol Implementation
*
* Copyright 2014 Marc-Andre Moreau <marcandre.moreau@gmail.com>
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "shadow.h"
2014-07-12 04:49:56 +04:00
#include "shadow_encoder.h"
#define TAG CLIENT_TAG("shadow")
int shadow_encoder_preferred_fps(rdpShadowEncoder* encoder)
{
/* Return preferred fps calculated according to the last
* sent frame id and last client-acknowledged frame id.
*/
return encoder->fps;
}
UINT32 shadow_encoder_inflight_frames(rdpShadowEncoder* encoder)
{
/* Return inflight frame count.
* If queueDepth is SUSPEND_FRAME_ACKNOWLEDGEMENT, count = 0
* Otherwise, calculate count =
* <last sent frame id> - <last client-acknowledged frame id>
* Note: This function is exported so that subsystem could
* implement its own strategy to tune fps.
*/
2019-11-06 17:24:51 +03:00
return (encoder->queueDepth == SUSPEND_FRAME_ACKNOWLEDGEMENT)
? 0
: encoder->frameId - encoder->lastAckframeId;
}
UINT32 shadow_encoder_create_frame_id(rdpShadowEncoder* encoder)
2014-07-14 03:42:57 +04:00
{
UINT32 frameId;
int inFlightFrames;
inFlightFrames = shadow_encoder_inflight_frames(encoder);
2014-07-14 03:42:57 +04:00
2016-09-20 10:25:13 +03:00
/*
* Calculate preferred fps according to how much frames are
* in-progress. Note that it only works when subsytem implementation
* calls shadow_encoder_preferred_fps and takes the suggestion.
2016-09-20 10:25:13 +03:00
*/
if (inFlightFrames > 1)
2014-07-14 03:42:57 +04:00
{
encoder->fps = (100 / (inFlightFrames + 1) * encoder->maxFps) / 100;
}
else
{
encoder->fps += 2;
if (encoder->fps > encoder->maxFps)
encoder->fps = encoder->maxFps;
}
if (encoder->fps < 1)
encoder->fps = 1;
frameId = ++encoder->frameId;
return frameId;
2014-07-14 03:42:57 +04:00
}
2016-09-20 10:25:13 +03:00
static int shadow_encoder_init_grid(rdpShadowEncoder* encoder)
2014-07-12 04:49:56 +04:00
{
int i, j, k;
int tileSize;
int tileCount;
2019-11-06 17:24:51 +03:00
encoder->gridWidth = ((encoder->width + (encoder->maxTileWidth - 1)) / encoder->maxTileWidth);
encoder->gridHeight =
((encoder->height + (encoder->maxTileHeight - 1)) / encoder->maxTileHeight);
2014-07-12 04:49:56 +04:00
tileSize = encoder->maxTileWidth * encoder->maxTileHeight * 4;
tileCount = encoder->gridWidth * encoder->gridHeight;
2019-11-06 17:24:51 +03:00
encoder->gridBuffer = (BYTE*)calloc(tileSize, tileCount);
2014-07-12 04:49:56 +04:00
if (!encoder->gridBuffer)
return -1;
2019-11-06 17:24:51 +03:00
encoder->grid = (BYTE**)calloc(tileCount, sizeof(BYTE*));
2014-07-12 04:49:56 +04:00
if (!encoder->grid)
return -1;
for (i = 0; i < encoder->gridHeight; i++)
{
for (j = 0; j < encoder->gridWidth; j++)
{
2014-09-17 23:19:35 +04:00
k = (i * encoder->gridWidth) + j;
2014-07-12 04:49:56 +04:00
encoder->grid[k] = &(encoder->gridBuffer[k * tileSize]);
}
}
return 0;
}
2016-09-20 10:25:13 +03:00
static int shadow_encoder_uninit_grid(rdpShadowEncoder* encoder)
2014-07-12 04:49:56 +04:00
{
if (encoder->gridBuffer)
{
free(encoder->gridBuffer);
encoder->gridBuffer = NULL;
}
if (encoder->grid)
{
free(encoder->grid);
encoder->grid = NULL;
}
encoder->gridWidth = 0;
encoder->gridHeight = 0;
return 0;
}
2016-09-20 10:25:13 +03:00
static int shadow_encoder_init_rfx(rdpShadowEncoder* encoder)
2014-07-12 04:49:56 +04:00
{
if (!encoder->rfx)
2020-12-15 18:11:22 +03:00
encoder->rfx = rfx_context_new(TRUE, encoder->server->settings->ThreadingFlags);
2014-07-12 04:49:56 +04:00
if (!encoder->rfx)
goto fail;
2016-03-01 18:56:36 +03:00
if (!rfx_context_reset(encoder->rfx, encoder->width, encoder->height))
goto fail;
2014-07-12 04:49:56 +04:00
encoder->rfx->mode = encoder->server->rfxMode;
2016-09-20 10:25:13 +03:00
rfx_context_set_pixel_format(encoder->rfx, PIXEL_FORMAT_BGRX32);
encoder->codecs |= FREERDP_CODEC_REMOTEFX;
return 1;
fail:
rfx_context_free(encoder->rfx);
return -1;
}
2014-07-12 04:49:56 +04:00
2016-09-20 10:25:13 +03:00
static int shadow_encoder_init_nsc(rdpShadowEncoder* encoder)
{
2019-11-06 17:24:51 +03:00
rdpContext* context = (rdpContext*)encoder->client;
2014-09-24 04:00:26 +04:00
rdpSettings* settings = context->settings;
if (!encoder->nsc)
encoder->nsc = nsc_context_new();
2014-07-12 04:49:56 +04:00
if (!encoder->nsc)
goto fail;
2014-07-12 04:49:56 +04:00
if (!nsc_context_reset(encoder->nsc, encoder->width, encoder->height))
goto fail;
2014-07-12 04:49:56 +04:00
2019-11-06 17:24:51 +03:00
if (!nsc_context_set_parameters(encoder->nsc, NSC_COLOR_LOSS_LEVEL,
settings->NSCodecColorLossLevel))
2019-10-04 11:13:43 +03:00
goto fail;
2019-11-06 17:24:51 +03:00
if (!nsc_context_set_parameters(encoder->nsc, NSC_ALLOW_SUBSAMPLING,
settings->NSCodecAllowSubsampling))
2019-10-04 11:13:43 +03:00
goto fail;
2019-11-06 17:24:51 +03:00
if (!nsc_context_set_parameters(encoder->nsc, NSC_DYNAMIC_COLOR_FIDELITY,
settings->NSCodecAllowDynamicColorFidelity))
2019-10-04 11:13:43 +03:00
goto fail;
if (!nsc_context_set_parameters(encoder->nsc, NSC_COLOR_FORMAT, PIXEL_FORMAT_BGRX32))
goto fail;
encoder->codecs |= FREERDP_CODEC_NSCODEC;
2014-07-15 20:50:47 +04:00
return 1;
fail:
nsc_context_free(encoder->nsc);
return -1;
2014-07-12 04:49:56 +04:00
}
2016-09-20 10:25:13 +03:00
static int shadow_encoder_init_planar(rdpShadowEncoder* encoder)
2014-07-12 04:49:56 +04:00
{
DWORD planarFlags = 0;
2019-11-06 17:24:51 +03:00
rdpContext* context = (rdpContext*)encoder->client;
rdpSettings* settings = context->settings;
if (settings->DrawAllowSkipAlpha)
planarFlags |= PLANAR_FORMAT_HEADER_NA;
2014-07-15 20:50:47 +04:00
planarFlags |= PLANAR_FORMAT_HEADER_RLE;
2014-07-15 20:50:47 +04:00
if (!encoder->planar)
2014-07-15 20:50:47 +04:00
{
2019-11-06 17:24:51 +03:00
encoder->planar = freerdp_bitmap_planar_context_new(planarFlags, encoder->maxTileWidth,
encoder->maxTileHeight);
2014-07-15 20:50:47 +04:00
}
2014-07-12 04:49:56 +04:00
if (!encoder->planar)
goto fail;
2019-11-06 17:24:51 +03:00
if (!freerdp_bitmap_planar_context_reset(encoder->planar, encoder->maxTileWidth,
encoder->maxTileHeight))
goto fail;
encoder->codecs |= FREERDP_CODEC_PLANAR;
return 1;
fail:
freerdp_bitmap_planar_context_free(encoder->planar);
return -1;
}
2016-09-20 10:25:13 +03:00
static int shadow_encoder_init_interleaved(rdpShadowEncoder* encoder)
{
if (!encoder->interleaved)
encoder->interleaved = bitmap_interleaved_context_new(TRUE);
if (!encoder->interleaved)
goto fail;
if (!bitmap_interleaved_context_reset(encoder->interleaved))
goto fail;
encoder->codecs |= FREERDP_CODEC_INTERLEAVED;
return 1;
fail:
bitmap_interleaved_context_free(encoder->interleaved);
return -1;
}
2016-09-20 10:25:13 +03:00
static int shadow_encoder_init_h264(rdpShadowEncoder* encoder)
{
if (!encoder->h264)
encoder->h264 = h264_context_new(TRUE);
if (!encoder->h264)
goto fail;
if (!h264_context_reset(encoder->h264, encoder->width, encoder->height))
goto fail;
encoder->h264->RateControlMode = encoder->server->h264RateControlMode;
encoder->h264->BitRate = encoder->server->h264BitRate;
encoder->h264->FrameRate = encoder->server->h264FrameRate;
encoder->h264->QP = encoder->server->h264QP;
2017-08-02 10:42:04 +03:00
encoder->codecs |= FREERDP_CODEC_AVC420 | FREERDP_CODEC_AVC444;
return 1;
fail:
h264_context_free(encoder->h264);
return -1;
}
2016-09-20 10:25:13 +03:00
static int shadow_encoder_init(rdpShadowEncoder* encoder)
{
encoder->width = encoder->server->screen->width;
encoder->height = encoder->server->screen->height;
encoder->maxTileWidth = 64;
encoder->maxTileHeight = 64;
shadow_encoder_init_grid(encoder);
if (!encoder->bs)
2019-11-06 17:24:51 +03:00
encoder->bs = Stream_New(NULL, encoder->maxTileWidth * encoder->maxTileHeight * 4);
if (!encoder->bs)
return -1;
return 1;
}
2016-09-20 10:25:13 +03:00
static int shadow_encoder_uninit_rfx(rdpShadowEncoder* encoder)
{
2014-07-15 20:50:47 +04:00
if (encoder->rfx)
{
rfx_context_free(encoder->rfx);
encoder->rfx = NULL;
}
2014-07-12 04:49:56 +04:00
encoder->codecs &= ~FREERDP_CODEC_REMOTEFX;
return 1;
}
2016-09-20 10:25:13 +03:00
static int shadow_encoder_uninit_nsc(rdpShadowEncoder* encoder)
{
2014-07-15 20:50:47 +04:00
if (encoder->nsc)
{
nsc_context_free(encoder->nsc);
encoder->nsc = NULL;
}
2014-07-12 04:49:56 +04:00
encoder->codecs &= ~FREERDP_CODEC_NSCODEC;
return 1;
}
2016-09-20 10:25:13 +03:00
static int shadow_encoder_uninit_planar(rdpShadowEncoder* encoder)
{
2014-07-15 20:50:47 +04:00
if (encoder->planar)
{
freerdp_bitmap_planar_context_free(encoder->planar);
encoder->planar = NULL;
}
2014-07-12 04:49:56 +04:00
encoder->codecs &= ~FREERDP_CODEC_PLANAR;
return 1;
}
2016-09-20 10:25:13 +03:00
static int shadow_encoder_uninit_interleaved(rdpShadowEncoder* encoder)
{
if (encoder->interleaved)
{
bitmap_interleaved_context_free(encoder->interleaved);
encoder->interleaved = NULL;
}
2014-07-12 04:49:56 +04:00
encoder->codecs &= ~FREERDP_CODEC_INTERLEAVED;
return 1;
}
2016-09-20 10:25:13 +03:00
static int shadow_encoder_uninit_h264(rdpShadowEncoder* encoder)
{
if (encoder->h264)
{
h264_context_free(encoder->h264);
2016-09-20 10:25:13 +03:00
encoder->h264 = NULL;
}
2017-08-02 10:42:04 +03:00
encoder->codecs &= ~(FREERDP_CODEC_AVC420 | FREERDP_CODEC_AVC444);
return 1;
}
2016-09-20 10:25:13 +03:00
static int shadow_encoder_uninit(rdpShadowEncoder* encoder)
{
shadow_encoder_uninit_grid(encoder);
if (encoder->bs)
2014-07-15 20:50:47 +04:00
{
Stream_Free(encoder->bs, TRUE);
encoder->bs = NULL;
}
if (encoder->codecs & FREERDP_CODEC_REMOTEFX)
{
shadow_encoder_uninit_rfx(encoder);
}
if (encoder->codecs & FREERDP_CODEC_NSCODEC)
{
shadow_encoder_uninit_nsc(encoder);
}
if (encoder->codecs & FREERDP_CODEC_PLANAR)
{
shadow_encoder_uninit_planar(encoder);
}
if (encoder->codecs & FREERDP_CODEC_INTERLEAVED)
{
shadow_encoder_uninit_interleaved(encoder);
2014-07-15 20:50:47 +04:00
}
2017-08-02 10:42:04 +03:00
if (encoder->codecs & (FREERDP_CODEC_AVC420 | FREERDP_CODEC_AVC444))
{
shadow_encoder_uninit_h264(encoder);
}
2014-07-15 20:50:47 +04:00
return 1;
}
int shadow_encoder_reset(rdpShadowEncoder* encoder)
{
int status;
UINT32 codecs = encoder->codecs;
2019-11-06 17:24:51 +03:00
rdpContext* context = (rdpContext*)encoder->client;
rdpSettings* settings = context->settings;
status = shadow_encoder_uninit(encoder);
if (status < 0)
2014-07-15 20:50:47 +04:00
return -1;
status = shadow_encoder_init(encoder);
if (status < 0)
return -1;
status = shadow_encoder_prepare(encoder, codecs);
if (status < 0)
return -1;
encoder->fps = 16;
encoder->maxFps = 32;
encoder->frameId = 0;
encoder->lastAckframeId = 0;
encoder->frameAck = settings->SurfaceFrameMarkerEnabled;
return 1;
}
int shadow_encoder_prepare(rdpShadowEncoder* encoder, UINT32 codecs)
{
int status;
2019-11-06 17:24:51 +03:00
if ((codecs & FREERDP_CODEC_REMOTEFX) && !(encoder->codecs & FREERDP_CODEC_REMOTEFX))
{
WLog_DBG(TAG, "initializing RemoteFX encoder");
status = shadow_encoder_init_rfx(encoder);
if (status < 0)
return -1;
}
2019-11-06 17:24:51 +03:00
if ((codecs & FREERDP_CODEC_NSCODEC) && !(encoder->codecs & FREERDP_CODEC_NSCODEC))
{
WLog_DBG(TAG, "initializing NSCodec encoder");
status = shadow_encoder_init_nsc(encoder);
if (status < 0)
return -1;
}
2019-11-06 17:24:51 +03:00
if ((codecs & FREERDP_CODEC_PLANAR) && !(encoder->codecs & FREERDP_CODEC_PLANAR))
{
WLog_DBG(TAG, "initializing planar bitmap encoder");
status = shadow_encoder_init_planar(encoder);
if (status < 0)
return -1;
}
2019-11-06 17:24:51 +03:00
if ((codecs & FREERDP_CODEC_INTERLEAVED) && !(encoder->codecs & FREERDP_CODEC_INTERLEAVED))
{
WLog_DBG(TAG, "initializing interleaved bitmap encoder");
status = shadow_encoder_init_interleaved(encoder);
if (status < 0)
return -1;
}
2019-11-06 17:24:51 +03:00
if ((codecs & (FREERDP_CODEC_AVC420 | FREERDP_CODEC_AVC444)) &&
!(encoder->codecs & (FREERDP_CODEC_AVC420 | FREERDP_CODEC_AVC444)))
{
WLog_DBG(TAG, "initializing H.264 encoder");
status = shadow_encoder_init_h264(encoder);
if (status < 0)
return -1;
}
return 1;
2014-07-15 20:50:47 +04:00
}
rdpShadowEncoder* shadow_encoder_new(rdpShadowClient* client)
2014-07-15 20:50:47 +04:00
{
rdpShadowEncoder* encoder;
rdpShadowServer* server = client->server;
2019-11-06 17:24:51 +03:00
encoder = (rdpShadowEncoder*)calloc(1, sizeof(rdpShadowEncoder));
2014-07-15 20:50:47 +04:00
if (!encoder)
return NULL;
encoder->client = client;
2014-07-15 20:50:47 +04:00
encoder->server = server;
2014-07-16 23:12:20 +04:00
encoder->fps = 16;
encoder->maxFps = 32;
2014-07-15 20:50:47 +04:00
if (shadow_encoder_init(encoder) < 0)
2014-11-17 02:34:17 +03:00
{
2016-09-20 10:25:13 +03:00
free(encoder);
2014-07-15 20:50:47 +04:00
return NULL;
2014-11-17 02:34:17 +03:00
}
2014-07-15 20:50:47 +04:00
return encoder;
}
void shadow_encoder_free(rdpShadowEncoder* encoder)
{
if (!encoder)
return;
shadow_encoder_uninit(encoder);
2014-07-12 04:49:56 +04:00
free(encoder);
}