Blame libfreerdp/gdi/video.c

Packit 1fb8d4
/**
Packit 1fb8d4
 * FreeRDP: A Remote Desktop Protocol Implementation
Packit 1fb8d4
 * Video Optimized Remoting Virtual Channel Extension for X11
Packit 1fb8d4
 *
Packit 1fb8d4
 * Copyright 2017 David Fort <contact@hardening-consulting.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 Service 5a9772
#include "../core/update.h"
Packit 1fb8d4
Packit 1fb8d4
#include <freerdp/client/geometry.h>
Packit 1fb8d4
#include <freerdp/client/video.h>
Packit 1fb8d4
#include <freerdp/gdi/gdi.h>
Packit 1fb8d4
#include <freerdp/gdi/video.h>
Packit 1fb8d4
#include <freerdp/gdi/region.h>
Packit 1fb8d4
Packit 1fb8d4
#define TAG FREERDP_TAG("video")
Packit 1fb8d4
Packit 1fb8d4
typedef struct
Packit 1fb8d4
{
Packit 1fb8d4
	VideoSurface base;
Packit 1fb8d4
	UINT32 scanline;
Packit 1fb8d4
	BYTE* image;
Packit 1fb8d4
} gdiVideoSurface;
Packit 1fb8d4
Packit 1fb8d4
void gdi_video_geometry_init(rdpGdi* gdi, GeometryClientContext* geom)
Packit 1fb8d4
{
Packit 1fb8d4
	gdi->geometry = geom;
Packit 1fb8d4
Packit 1fb8d4
	if (gdi->video)
Packit 1fb8d4
	{
Packit 1fb8d4
		VideoClientContext* video = gdi->video;
Packit 1fb8d4
		video->setGeometry(video, gdi->geometry);
Packit 1fb8d4
	}
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
void gdi_video_geometry_uninit(rdpGdi* gdi, GeometryClientContext* geom)
Packit 1fb8d4
{
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static VideoSurface* gdiVideoCreateSurface(VideoClientContext* video, BYTE* data, UINT32 x,
Packit Service 5a9772
                                           UINT32 y, UINT32 width, UINT32 height)
Packit 1fb8d4
{
Packit 1fb8d4
	rdpGdi* gdi = (rdpGdi*)video->custom;
Packit 1fb8d4
	gdiVideoSurface* ret = calloc(1, sizeof(*ret));
Packit 1fb8d4
	UINT32 bpp;
Packit 1fb8d4
Packit 1fb8d4
	if (!ret)
Packit 1fb8d4
		return NULL;
Packit 1fb8d4
Packit 1fb8d4
	bpp = GetBytesPerPixel(gdi->dstFormat);
Packit 1fb8d4
	ret->base.data = data;
Packit 1fb8d4
	ret->base.x = x;
Packit 1fb8d4
	ret->base.y = y;
Packit 1fb8d4
	ret->base.w = width;
Packit 1fb8d4
	ret->base.h = height;
Packit 1fb8d4
	ret->scanline = width * bpp;
Packit 1fb8d4
	ret->image = _aligned_malloc(ret->scanline * height, 16);
Packit 1fb8d4
Packit 1fb8d4
	if (!ret->image)
Packit 1fb8d4
	{
Packit 1fb8d4
		WLog_ERR(TAG, "unable to create surface image");
Packit 1fb8d4
		free(ret);
Packit 1fb8d4
		return NULL;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	return &ret->base;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static BOOL gdiVideoShowSurface(VideoClientContext* video, VideoSurface* surface)
Packit 1fb8d4
{
Packit Service 5a9772
	BOOL rc = FALSE;
Packit 1fb8d4
	rdpGdi* gdi = (rdpGdi*)video->custom;
Packit 1fb8d4
	gdiVideoSurface* gdiSurface = (gdiVideoSurface*)surface;
Packit 1fb8d4
	RECTANGLE_16 surfaceRect;
Packit 1fb8d4
	rdpUpdate* update = gdi->context->update;
Packit 1fb8d4
	surfaceRect.left = surface->x;
Packit 1fb8d4
	surfaceRect.top = surface->y;
Packit 1fb8d4
	surfaceRect.right = surface->x + surface->w;
Packit 1fb8d4
	surfaceRect.bottom = surface->y + surface->h;
Packit Service 5a9772
Packit Service 5a9772
	if (!update_begin_paint(update))
Packit Service 5a9772
		goto fail;
Packit Service 5a9772
Packit Service 5a9772
	if ((gdi->width < 0) || (gdi->height < 0))
Packit Service 5a9772
		goto fail;
Packit Service 5a9772
	else
Packit 1fb8d4
	{
Packit 1fb8d4
		const UINT32 nXSrc = surface->x;
Packit 1fb8d4
		const UINT32 nYSrc = surface->y;
Packit 1fb8d4
		const UINT32 nXDst = nXSrc;
Packit 1fb8d4
		const UINT32 nYDst = nYSrc;
Packit Service 5a9772
		const UINT32 width = (surface->w + surface->x < (UINT32)gdi->width)
Packit Service 5a9772
		                         ? surface->w
Packit Service 5a9772
		                         : (UINT32)gdi->width - surface->x;
Packit Service 5a9772
		const UINT32 height = (surface->h + surface->y < (UINT32)gdi->height)
Packit Service 5a9772
		                          ? surface->h
Packit Service 5a9772
		                          : (UINT32)gdi->height - surface->y;
Packit Service 5a9772
Packit Service 5a9772
		if (!freerdp_image_copy(gdi->primary_buffer, gdi->primary->hdc->format, gdi->stride, nXDst,
Packit Service 5a9772
		                        nYDst, width, height, surface->data, gdi->primary->hdc->format,
Packit 1fb8d4
		                        gdiSurface->scanline, 0, 0, NULL, FREERDP_FLIP_NONE))
Packit Service 5a9772
			goto fail;
Packit Service 5a9772
Packit Service 5a9772
		if ((nXDst > INT32_MAX) || (nYDst > INT32_MAX) || (width > INT32_MAX) ||
Packit Service 5a9772
		    (height > INT32_MAX))
Packit Service 5a9772
			goto fail;
Packit 1fb8d4
Packit Service 5a9772
		gdi_InvalidateRegion(gdi->primary->hdc, (INT32)nXDst, (INT32)nYDst, (INT32)width,
Packit Service 5a9772
		                     (INT32)height);
Packit 1fb8d4
	}
Packit Service 5a9772
Packit Service 5a9772
	rc = TRUE;
Packit Service 5a9772
fail:
Packit Service 5a9772
Packit Service 5a9772
	if (!update_end_paint(update))
Packit Service 5a9772
		return FALSE;
Packit Service 5a9772
Packit Service 5a9772
	return rc;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static BOOL gdiVideoDeleteSurface(VideoClientContext* video, VideoSurface* surface)
Packit 1fb8d4
{
Packit 1fb8d4
	gdiVideoSurface* gdiSurface = (gdiVideoSurface*)surface;
Packit 1fb8d4
Packit 1fb8d4
	if (gdiSurface)
Packit 1fb8d4
		_aligned_free(gdiSurface->image);
Packit 1fb8d4
Packit 1fb8d4
	free(gdiSurface);
Packit 1fb8d4
	return TRUE;
Packit 1fb8d4
}
Packit 1fb8d4
void gdi_video_control_init(rdpGdi* gdi, VideoClientContext* video)
Packit 1fb8d4
{
Packit 1fb8d4
	gdi->video = video;
Packit 1fb8d4
	video->custom = gdi;
Packit 1fb8d4
	video->createSurface = gdiVideoCreateSurface;
Packit 1fb8d4
	video->showSurface = gdiVideoShowSurface;
Packit 1fb8d4
	video->deleteSurface = gdiVideoDeleteSurface;
Packit 1fb8d4
	video->setGeometry(video, gdi->geometry);
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
void gdi_video_control_uninit(rdpGdi* gdi, VideoClientContext* video)
Packit 1fb8d4
{
Packit 1fb8d4
	gdi->video = NULL;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static void gdi_video_timer(void* context, TimerEventArgs* timer)
Packit 1fb8d4
{
Packit 1fb8d4
	rdpContext* ctx = (rdpContext*)context;
Packit 1fb8d4
	rdpGdi* gdi = ctx->gdi;
Packit 1fb8d4
Packit 1fb8d4
	if (gdi && gdi->video)
Packit 1fb8d4
		gdi->video->timer(gdi->video, timer->now);
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
void gdi_video_data_init(rdpGdi* gdi, VideoClientContext* video)
Packit 1fb8d4
{
Packit 1fb8d4
	PubSub_SubscribeTimer(gdi->context->pubSub, gdi_video_timer);
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
void gdi_video_data_uninit(rdpGdi* gdi, VideoClientContext* context)
Packit 1fb8d4
{
Packit 1fb8d4
	PubSub_UnsubscribeTimer(gdi->context->pubSub, gdi_video_timer);
Packit 1fb8d4
}