FreeRDP
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Modules Pages
video.c
1
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
30void gdi_video_geometry_init(rdpGdi* gdi, GeometryClientContext* geom)
31{
32 WINPR_ASSERT(gdi);
33 WINPR_ASSERT(geom);
34
35 gdi->geometry = geom;
36
37 if (gdi->video)
38 {
39 VideoClientContext* video = gdi->video;
40
41 WINPR_ASSERT(video);
42 WINPR_ASSERT(video->setGeometry);
43 video->setGeometry(video, gdi->geometry);
44 }
45}
46
47void gdi_video_geometry_uninit(rdpGdi* gdi, GeometryClientContext* geom)
48{
49 WINPR_ASSERT(gdi);
50 WINPR_ASSERT(geom);
51 WINPR_UNUSED(gdi);
52 WINPR_UNUSED(geom);
53}
54
55static VideoSurface* gdiVideoCreateSurface(WINPR_ATTR_UNUSED VideoClientContext* video, UINT32 x,
56 UINT32 y, UINT32 width, UINT32 height)
57{
58 return VideoClient_CreateCommonContext(sizeof(VideoSurface), x, y, width, height);
59}
60
61static BOOL gdiVideoShowSurface(VideoClientContext* video, const VideoSurface* surface,
62 UINT32 destinationWidth, UINT32 destinationHeight)
63{
64 BOOL rc = FALSE;
65 rdpGdi* gdi = NULL;
66 rdpUpdate* update = NULL;
67
68 WINPR_ASSERT(video);
69 WINPR_ASSERT(surface);
70
71 gdi = (rdpGdi*)video->custom;
72 WINPR_ASSERT(gdi);
73 WINPR_ASSERT(gdi->context);
74
75 update = gdi->context->update;
76 WINPR_ASSERT(update);
77
78 if (!update_begin_paint(update))
79 goto fail;
80
81 if ((gdi->width < 0) || (gdi->height < 0))
82 goto fail;
83 else
84 {
85 const UINT32 nXSrc = surface->x;
86 const UINT32 nYSrc = surface->y;
87 const UINT32 nXDst = nXSrc;
88 const UINT32 nYDst = nYSrc;
89 const UINT32 width = (destinationWidth + surface->x < (UINT32)gdi->width)
90 ? destinationWidth
91 : (UINT32)gdi->width - surface->x;
92 const UINT32 height = (destinationHeight + surface->y < (UINT32)gdi->height)
93 ? destinationHeight
94 : (UINT32)gdi->height - surface->y;
95
96 WINPR_ASSERT(gdi->primary_buffer);
97 WINPR_ASSERT(gdi->primary);
98 WINPR_ASSERT(gdi->primary->hdc);
99
100 if (!freerdp_image_scale(gdi->primary_buffer, gdi->primary->hdc->format, gdi->stride, nXDst,
101 nYDst, width, height, surface->data, surface->format,
102 surface->scanline, 0, 0, surface->w, surface->h))
103 goto fail;
104
105 if ((nXDst > INT32_MAX) || (nYDst > INT32_MAX) || (width > INT32_MAX) ||
106 (height > INT32_MAX))
107 goto fail;
108
109 gdi_InvalidateRegion(gdi->primary->hdc, (INT32)nXDst, (INT32)nYDst, (INT32)width,
110 (INT32)height);
111 }
112
113 rc = TRUE;
114fail:
115
116 if (!update_end_paint(update))
117 return FALSE;
118
119 return rc;
120}
121
122static BOOL gdiVideoDeleteSurface(VideoClientContext* video, VideoSurface* surface)
123{
124 WINPR_UNUSED(video);
125 VideoClient_DestroyCommonContext(surface);
126 return TRUE;
127}
128
129void gdi_video_control_init(rdpGdi* gdi, VideoClientContext* video)
130{
131 WINPR_ASSERT(gdi);
132 WINPR_ASSERT(video);
133
134 gdi->video = video;
135 video->custom = gdi;
136 video->createSurface = gdiVideoCreateSurface;
137 video->showSurface = gdiVideoShowSurface;
138 video->deleteSurface = gdiVideoDeleteSurface;
139 video->setGeometry(video, gdi->geometry);
140}
141
142void gdi_video_control_uninit(rdpGdi* gdi, WINPR_ATTR_UNUSED VideoClientContext* video)
143{
144 WINPR_ASSERT(gdi);
145 gdi->video = NULL;
146}
147
148static void gdi_video_timer(void* context, const TimerEventArgs* timer)
149{
150 rdpContext* ctx = (rdpContext*)context;
151 rdpGdi* gdi = NULL;
152
153 WINPR_ASSERT(ctx);
154 WINPR_ASSERT(timer);
155
156 gdi = ctx->gdi;
157
158 if (gdi && gdi->video)
159 gdi->video->timer(gdi->video, timer->now);
160}
161
162void gdi_video_data_init(rdpGdi* gdi, WINPR_ATTR_UNUSED VideoClientContext* video)
163{
164 WINPR_ASSERT(gdi);
165 WINPR_ASSERT(gdi->context);
166 PubSub_SubscribeTimer(gdi->context->pubSub, gdi_video_timer);
167}
168
169void gdi_video_data_uninit(rdpGdi* gdi, WINPR_ATTR_UNUSED VideoClientContext* context)
170{
171 WINPR_ASSERT(gdi);
172 WINPR_ASSERT(gdi->context);
173 PubSub_UnsubscribeTimer(gdi->context->pubSub, gdi_video_timer);
174}
175
176VideoSurface* VideoClient_CreateCommonContext(size_t size, UINT32 x, UINT32 y, UINT32 w, UINT32 h)
177{
178 VideoSurface* ret = NULL;
179
180 WINPR_ASSERT(size >= sizeof(VideoSurface));
181
182 ret = calloc(1, size);
183 if (!ret)
184 return NULL;
185
186 ret->format = PIXEL_FORMAT_BGRX32;
187 ret->x = x;
188 ret->y = y;
189 ret->w = w;
190 ret->h = h;
191 ret->alignedWidth = ret->w + 32 - ret->w % 16;
192 ret->alignedHeight = ret->h + 32 - ret->h % 16;
193
194 ret->scanline = ret->alignedWidth * FreeRDPGetBytesPerPixel(ret->format);
195 ret->data = winpr_aligned_malloc(1ull * ret->scanline * ret->alignedHeight, 64);
196 if (!ret->data)
197 goto fail;
198 return ret;
199fail:
200 VideoClient_DestroyCommonContext(ret);
201 return NULL;
202}
203
204void VideoClient_DestroyCommonContext(VideoSurface* surface)
205{
206 if (!surface)
207 return;
208 winpr_aligned_free(surface->data);
209 free(surface);
210}
an implementation of surface used by the video channel