FreeRDP
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 
30 void 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 
47 void 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 
55 static VideoSurface* gdiVideoCreateSurface(VideoClientContext* video, UINT32 x, UINT32 y,
56  UINT32 width, UINT32 height)
57 {
58  return VideoClient_CreateCommonContext(sizeof(VideoSurface), x, y, width, height);
59 }
60 
61 static 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;
114 fail:
115 
116  if (!update_end_paint(update))
117  return FALSE;
118 
119  return rc;
120 }
121 
122 static BOOL gdiVideoDeleteSurface(VideoClientContext* video, VideoSurface* surface)
123 {
124  WINPR_UNUSED(video);
125  VideoClient_DestroyCommonContext(surface);
126  return TRUE;
127 }
128 
129 void 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 
142 void gdi_video_control_uninit(rdpGdi* gdi, VideoClientContext* video)
143 {
144  WINPR_ASSERT(gdi);
145  gdi->video = NULL;
146 }
147 
148 static 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 
162 void gdi_video_data_init(rdpGdi* gdi, VideoClientContext* video)
163 {
164  WINPR_ASSERT(gdi);
165  WINPR_ASSERT(gdi->context);
166  PubSub_SubscribeTimer(gdi->context->pubSub, gdi_video_timer);
167 }
168 
169 void gdi_video_data_uninit(rdpGdi* gdi, VideoClientContext* context)
170 {
171  WINPR_ASSERT(gdi);
172  WINPR_ASSERT(gdi->context);
173  PubSub_UnsubscribeTimer(gdi->context->pubSub, gdi_video_timer);
174 }
175 
176 VideoSurface* 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;
199 fail:
200  VideoClient_DestroyCommonContext(ret);
201  return NULL;
202 }
203 
204 void 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
Definition: client/video.h:36