Coverage Report

Created: 2024-05-20 06:11

/src/FreeRDP/libfreerdp/gdi/video.c
Line
Count
Source (jump to first uncovered line)
1
/**
2
 * FreeRDP: A Remote Desktop Protocol Implementation
3
 * Video Optimized Remoting Virtual Channel Extension for X11
4
 *
5
 * Copyright 2017 David Fort <contact@hardening-consulting.com>
6
 *
7
 * Licensed under the Apache License, Version 2.0 (the "License");
8
 * you may not use this file except in compliance with the License.
9
 * You may obtain a copy of the License at
10
 *
11
 *     http://www.apache.org/licenses/LICENSE-2.0
12
 *
13
 * Unless required by applicable law or agreed to in writing, software
14
 * distributed under the License is distributed on an "AS IS" BASIS,
15
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
 * See the License for the specific language governing permissions and
17
 * limitations under the License.
18
 */
19
20
#include "../core/update.h"
21
22
#include <winpr/assert.h>
23
24
#include <freerdp/client/geometry.h>
25
#include <freerdp/client/video.h>
26
#include <freerdp/gdi/gdi.h>
27
#include <freerdp/gdi/video.h>
28
#include <freerdp/gdi/region.h>
29
30
#define TAG FREERDP_TAG("video")
31
32
void gdi_video_geometry_init(rdpGdi* gdi, GeometryClientContext* geom)
33
0
{
34
0
  WINPR_ASSERT(gdi);
35
0
  WINPR_ASSERT(geom);
36
37
0
  gdi->geometry = geom;
38
39
0
  if (gdi->video)
40
0
  {
41
0
    VideoClientContext* video = gdi->video;
42
43
0
    WINPR_ASSERT(video);
44
0
    WINPR_ASSERT(video->setGeometry);
45
0
    video->setGeometry(video, gdi->geometry);
46
0
  }
47
0
}
48
49
void gdi_video_geometry_uninit(rdpGdi* gdi, GeometryClientContext* geom)
50
0
{
51
0
  WINPR_ASSERT(gdi);
52
0
  WINPR_ASSERT(geom);
53
0
  WINPR_UNUSED(gdi);
54
0
  WINPR_UNUSED(geom);
55
0
}
56
57
static VideoSurface* gdiVideoCreateSurface(VideoClientContext* video, UINT32 x, UINT32 y,
58
                                           UINT32 width, UINT32 height)
59
0
{
60
0
  return VideoClient_CreateCommonContext(sizeof(VideoSurface), x, y, width, height);
61
0
}
62
63
static BOOL gdiVideoShowSurface(VideoClientContext* video, const VideoSurface* surface,
64
                                UINT32 destinationWidth, UINT32 destinationHeight)
65
0
{
66
0
  BOOL rc = FALSE;
67
0
  rdpGdi* gdi = NULL;
68
0
  rdpUpdate* update = NULL;
69
70
0
  WINPR_ASSERT(video);
71
0
  WINPR_ASSERT(surface);
72
73
0
  gdi = (rdpGdi*)video->custom;
74
0
  WINPR_ASSERT(gdi);
75
0
  WINPR_ASSERT(gdi->context);
76
77
0
  update = gdi->context->update;
78
0
  WINPR_ASSERT(update);
79
80
0
  if (!update_begin_paint(update))
81
0
    goto fail;
82
83
0
  if ((gdi->width < 0) || (gdi->height < 0))
84
0
    goto fail;
85
0
  else
86
0
  {
87
0
    const UINT32 nXSrc = surface->x;
88
0
    const UINT32 nYSrc = surface->y;
89
0
    const UINT32 nXDst = nXSrc;
90
0
    const UINT32 nYDst = nYSrc;
91
0
    const UINT32 width = (destinationWidth + surface->x < (UINT32)gdi->width)
92
0
                             ? destinationWidth
93
0
                             : (UINT32)gdi->width - surface->x;
94
0
    const UINT32 height = (destinationHeight + surface->y < (UINT32)gdi->height)
95
0
                              ? destinationHeight
96
0
                              : (UINT32)gdi->height - surface->y;
97
98
0
    WINPR_ASSERT(gdi->primary_buffer);
99
0
    WINPR_ASSERT(gdi->primary);
100
0
    WINPR_ASSERT(gdi->primary->hdc);
101
102
0
    if (!freerdp_image_scale(gdi->primary_buffer, gdi->primary->hdc->format, gdi->stride, nXDst,
103
0
                             nYDst, width, height, surface->data, surface->format,
104
0
                             surface->scanline, 0, 0, surface->w, surface->h))
105
0
      goto fail;
106
107
0
    if ((nXDst > INT32_MAX) || (nYDst > INT32_MAX) || (width > INT32_MAX) ||
108
0
        (height > INT32_MAX))
109
0
      goto fail;
110
111
0
    gdi_InvalidateRegion(gdi->primary->hdc, (INT32)nXDst, (INT32)nYDst, (INT32)width,
112
0
                         (INT32)height);
113
0
  }
114
115
0
  rc = TRUE;
116
0
fail:
117
118
0
  if (!update_end_paint(update))
119
0
    return FALSE;
120
121
0
  return rc;
122
0
}
123
124
static BOOL gdiVideoDeleteSurface(VideoClientContext* video, VideoSurface* surface)
125
0
{
126
0
  WINPR_UNUSED(video);
127
0
  VideoClient_DestroyCommonContext(surface);
128
0
  return TRUE;
129
0
}
130
131
void gdi_video_control_init(rdpGdi* gdi, VideoClientContext* video)
132
0
{
133
0
  WINPR_ASSERT(gdi);
134
0
  WINPR_ASSERT(video);
135
136
0
  gdi->video = video;
137
0
  video->custom = gdi;
138
0
  video->createSurface = gdiVideoCreateSurface;
139
0
  video->showSurface = gdiVideoShowSurface;
140
0
  video->deleteSurface = gdiVideoDeleteSurface;
141
0
  video->setGeometry(video, gdi->geometry);
142
0
}
143
144
void gdi_video_control_uninit(rdpGdi* gdi, VideoClientContext* video)
145
0
{
146
0
  WINPR_ASSERT(gdi);
147
0
  gdi->video = NULL;
148
0
}
149
150
static void gdi_video_timer(void* context, const TimerEventArgs* timer)
151
0
{
152
0
  rdpContext* ctx = (rdpContext*)context;
153
0
  rdpGdi* gdi = NULL;
154
155
0
  WINPR_ASSERT(ctx);
156
0
  WINPR_ASSERT(timer);
157
158
0
  gdi = ctx->gdi;
159
160
0
  if (gdi && gdi->video)
161
0
    gdi->video->timer(gdi->video, timer->now);
162
0
}
163
164
void gdi_video_data_init(rdpGdi* gdi, VideoClientContext* video)
165
0
{
166
0
  WINPR_ASSERT(gdi);
167
0
  WINPR_ASSERT(gdi->context);
168
0
  PubSub_SubscribeTimer(gdi->context->pubSub, gdi_video_timer);
169
0
}
170
171
void gdi_video_data_uninit(rdpGdi* gdi, VideoClientContext* context)
172
0
{
173
0
  WINPR_ASSERT(gdi);
174
0
  WINPR_ASSERT(gdi->context);
175
0
  PubSub_UnsubscribeTimer(gdi->context->pubSub, gdi_video_timer);
176
0
}
177
178
VideoSurface* VideoClient_CreateCommonContext(size_t size, UINT32 x, UINT32 y, UINT32 w, UINT32 h)
179
0
{
180
0
  VideoSurface* ret = NULL;
181
182
0
  WINPR_ASSERT(size >= sizeof(VideoSurface));
183
184
0
  ret = calloc(1, size);
185
0
  if (!ret)
186
0
    return NULL;
187
188
0
  ret->format = PIXEL_FORMAT_BGRX32;
189
0
  ret->x = x;
190
0
  ret->y = y;
191
0
  ret->w = w;
192
0
  ret->h = h;
193
0
  ret->alignedWidth = ret->w + 32 - ret->w % 16;
194
0
  ret->alignedHeight = ret->h + 32 - ret->h % 16;
195
196
0
  ret->scanline = ret->alignedWidth * FreeRDPGetBytesPerPixel(ret->format);
197
0
  ret->data = winpr_aligned_malloc(1ull * ret->scanline * ret->alignedHeight, 64);
198
0
  if (!ret->data)
199
0
    goto fail;
200
0
  return ret;
201
0
fail:
202
0
  VideoClient_DestroyCommonContext(ret);
203
0
  return NULL;
204
0
}
205
206
void VideoClient_DestroyCommonContext(VideoSurface* surface)
207
0
{
208
0
  if (!surface)
209
0
    return;
210
0
  winpr_aligned_free(surface->data);
211
0
  free(surface);
212
0
}