Blame server/shadow/shadow_encoder.c

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