|
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 |
}
|