Merge pull request #2091 from ptsekov/software-gdi-improvements
[platform/upstream/freerdp.git] / server / shadow / shadow_encoder.c
1 /**
2  * FreeRDP: A Remote Desktop Protocol Implementation
3  *
4  * Copyright 2014 Marc-Andre Moreau <marcandre.moreau@gmail.com>
5  *
6  * Licensed under the Apache License, Version 2.0 (the "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  *     http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  */
18
19 #ifdef HAVE_CONFIG_H
20 #include "config.h"
21 #endif
22
23 #include "shadow.h"
24
25 #include "shadow_encoder.h"
26
27 int shadow_encoder_create_frame_id(rdpShadowEncoder* encoder)
28 {
29         UINT32 frameId;
30         int inFlightFrames;
31         SURFACE_FRAME* frame;
32
33         inFlightFrames = ListDictionary_Count(encoder->frameList);
34
35         if (inFlightFrames > encoder->frameAck)
36         {
37                 encoder->fps = (100 / (inFlightFrames + 1) * encoder->maxFps) / 100;
38         }
39         else
40         {
41                 encoder->fps += 2;
42
43                 if (encoder->fps > encoder->maxFps)
44                         encoder->fps = encoder->maxFps;
45         }
46
47         if (encoder->fps < 1)
48                 encoder->fps = 1;
49
50         frame = (SURFACE_FRAME*) malloc(sizeof(SURFACE_FRAME));
51
52         if (!frame)
53                 return -1;
54
55         frameId = frame->frameId = ++encoder->frameId;
56         ListDictionary_Add(encoder->frameList, (void*) (size_t) frame->frameId, frame);
57
58         return (int) frame->frameId;
59 }
60
61 int shadow_encoder_init_grid(rdpShadowEncoder* encoder)
62 {
63         int i, j, k;
64         int tileSize;
65         int tileCount;
66
67         encoder->gridWidth = ((encoder->width + (encoder->maxTileWidth - 1)) / encoder->maxTileWidth);
68         encoder->gridHeight = ((encoder->height + (encoder->maxTileHeight - 1)) / encoder->maxTileHeight);
69
70         tileSize = encoder->maxTileWidth * encoder->maxTileHeight * 4;
71         tileCount = encoder->gridWidth * encoder->gridHeight;
72
73         encoder->gridBuffer = (BYTE*) malloc(tileSize * tileCount);
74
75         if (!encoder->gridBuffer)
76                 return -1;
77
78         encoder->grid = (BYTE**) malloc(tileCount * sizeof(BYTE*));
79
80         if (!encoder->grid)
81                 return -1;
82
83         for (i = 0; i < encoder->gridHeight; i++)
84         {
85                 for (j = 0; j < encoder->gridWidth; j++)
86                 {
87                         k = (i * encoder->gridHeight) + j;
88                         encoder->grid[k] = &(encoder->gridBuffer[k * tileSize]);
89                 }
90         }
91
92         return 0;
93 }
94
95 int shadow_encoder_uninit_grid(rdpShadowEncoder* encoder)
96 {
97         if (encoder->gridBuffer)
98         {
99                 free(encoder->gridBuffer);
100                 encoder->gridBuffer = NULL;
101         }
102
103         if (encoder->grid)
104         {
105                 free(encoder->grid);
106                 encoder->grid = NULL;
107         }
108
109         encoder->gridWidth = 0;
110         encoder->gridHeight = 0;
111
112         return 0;
113 }
114
115 int shadow_encoder_init_rfx(rdpShadowEncoder* encoder)
116 {
117         if (!encoder->rfx)
118                 encoder->rfx = rfx_context_new(TRUE);
119
120         if (!encoder->rfx)
121                 return -1;
122
123         encoder->rfx->mode = RLGR3;
124         encoder->rfx->width = encoder->width;
125         encoder->rfx->height = encoder->height;
126
127         rfx_context_set_pixel_format(encoder->rfx, RDP_PIXEL_FORMAT_B8G8R8A8);
128
129         if (!encoder->frameList)
130         {
131                 encoder->fps = 16;
132                 encoder->maxFps = 32;
133                 encoder->frameId = 0;
134                 encoder->frameAck = TRUE;
135                 encoder->frameList = ListDictionary_New(TRUE);
136         }
137
138         encoder->codecs |= SHADOW_CODEC_REMOTEFX;
139
140         return 1;
141 }
142
143 int shadow_encoder_init_nsc(rdpShadowEncoder* encoder)
144 {
145         if (!encoder->nsc)
146                 encoder->nsc = nsc_context_new();
147
148         if (!encoder->nsc)
149                 return -1;
150
151         nsc_context_set_pixel_format(encoder->nsc, RDP_PIXEL_FORMAT_B8G8R8A8);
152
153         if (!encoder->frameList)
154         {
155                 encoder->fps = 16;
156                 encoder->maxFps = 32;
157                 encoder->frameId = 0;
158                 encoder->frameAck = TRUE;
159                 encoder->frameList = ListDictionary_New(TRUE);
160         }
161
162         encoder->codecs |= SHADOW_CODEC_NSCODEC;
163
164         return 1;
165 }
166
167 int shadow_encoder_init_bitmap(rdpShadowEncoder* encoder)
168 {
169         DWORD planarFlags;
170
171         planarFlags = PLANAR_FORMAT_HEADER_NA;
172         planarFlags |= PLANAR_FORMAT_HEADER_RLE;
173
174         if (!encoder->planar)
175         {
176                 encoder->planar = freerdp_bitmap_planar_context_new(planarFlags,
177                                 encoder->maxTileWidth, encoder->maxTileHeight);
178         }
179
180         if (!encoder->planar)
181                 return -1;
182
183         if (!encoder->bts)
184                 encoder->bts = Stream_New(NULL, encoder->maxTileWidth * encoder->maxTileHeight * 4);
185
186         if (!encoder->bts)
187                 return -1;
188
189         encoder->codecs |= SHADOW_CODEC_BITMAP;
190
191         return 1;
192 }
193
194 int shadow_encoder_init(rdpShadowEncoder* encoder)
195 {
196         encoder->maxTileWidth = 64;
197         encoder->maxTileHeight = 64;
198
199         shadow_encoder_init_grid(encoder);
200
201         if (!encoder->bs)
202                 encoder->bs = Stream_New(NULL, encoder->maxTileWidth * encoder->maxTileHeight * 4);
203
204         if (!encoder->bs)
205                 return -1;
206
207         return 1;
208 }
209
210 int shadow_encoder_uninit_rfx(rdpShadowEncoder* encoder)
211 {
212         if (encoder->rfx)
213         {
214                 rfx_context_free(encoder->rfx);
215                 encoder->rfx = NULL;
216         }
217
218         if (encoder->frameList)
219         {
220                 ListDictionary_Free(encoder->frameList);
221                 encoder->frameList = NULL;
222         }
223
224         encoder->codecs &= ~SHADOW_CODEC_REMOTEFX;
225
226         return 1;
227 }
228
229 int shadow_encoder_uninit_nsc(rdpShadowEncoder* encoder)
230 {
231         if (encoder->nsc)
232         {
233                 nsc_context_free(encoder->nsc);
234                 encoder->nsc = NULL;
235         }
236
237         if (encoder->frameList)
238         {
239                 ListDictionary_Free(encoder->frameList);
240                 encoder->frameList = NULL;
241         }
242
243         encoder->codecs &= ~SHADOW_CODEC_NSCODEC;
244
245         return 1;
246 }
247
248 int shadow_encoder_uninit_bitmap(rdpShadowEncoder* encoder)
249 {
250         if (encoder->planar)
251         {
252                 freerdp_bitmap_planar_context_free(encoder->planar);
253                 encoder->planar = NULL;
254         }
255
256         if (encoder->bts)
257         {
258                 Stream_Free(encoder->bts, TRUE);
259                 encoder->bts = NULL;
260         }
261
262         encoder->codecs &= ~SHADOW_CODEC_BITMAP;
263
264         return 1;
265 }
266
267 int shadow_encoder_uninit(rdpShadowEncoder* encoder)
268 {
269         shadow_encoder_uninit_grid(encoder);
270
271         if (encoder->bs)
272         {
273                 Stream_Free(encoder->bs, TRUE);
274                 encoder->bs = NULL;
275         }
276
277         if (encoder->codecs & SHADOW_CODEC_REMOTEFX)
278         {
279                 shadow_encoder_uninit_rfx(encoder);
280         }
281
282         if (encoder->codecs & SHADOW_CODEC_NSCODEC)
283         {
284                 shadow_encoder_uninit_nsc(encoder);
285         }
286
287         if (encoder->codecs & SHADOW_CODEC_BITMAP)
288         {
289                 shadow_encoder_uninit_bitmap(encoder);
290         }
291
292         return 1;
293 }
294
295 int shadow_encoder_reset(rdpShadowEncoder* encoder)
296 {
297         int status;
298         UINT32 codecs = encoder->codecs;
299
300         status = shadow_encoder_uninit(encoder);
301
302         if (status < 0)
303                 return -1;
304
305         status = shadow_encoder_init(encoder);
306
307         if (status < 0)
308                 return -1;
309
310         status = shadow_encoder_prepare(encoder, codecs);
311
312         if (status < 0)
313                 return -1;
314
315         return 1;
316 }
317
318 int shadow_encoder_prepare(rdpShadowEncoder* encoder, UINT32 codecs)
319 {
320         int status;
321
322         if ((codecs & SHADOW_CODEC_REMOTEFX) && !(encoder->codecs & SHADOW_CODEC_REMOTEFX))
323         {
324                 status = shadow_encoder_init_rfx(encoder);
325
326                 if (status < 0)
327                         return -1;
328         }
329
330         if ((codecs & SHADOW_CODEC_NSCODEC) && !(encoder->codecs & SHADOW_CODEC_NSCODEC))
331         {
332                 status = shadow_encoder_init_nsc(encoder);
333
334                 if (status < 0)
335                         return -1;
336         }
337
338         if ((codecs & SHADOW_CODEC_BITMAP) && !(encoder->codecs & SHADOW_CODEC_BITMAP))
339         {
340                 status = shadow_encoder_init_bitmap(encoder);
341
342                 if (status < 0)
343                         return -1;
344         }
345
346         return 1;
347 }
348
349 rdpShadowEncoder* shadow_encoder_new(rdpShadowServer* server)
350 {
351         rdpShadowEncoder* encoder;
352
353         encoder = (rdpShadowEncoder*) calloc(1, sizeof(rdpShadowEncoder));
354
355         if (!encoder)
356                 return NULL;
357
358         encoder->server = server;
359
360         encoder->fps = 16;
361         encoder->maxFps = 32;
362
363         encoder->width = server->screen->width;
364         encoder->height = server->screen->height;
365
366         if (shadow_encoder_init(encoder) < 0)
367                 return NULL;
368
369         return encoder;
370 }
371
372 void shadow_encoder_free(rdpShadowEncoder* encoder)
373 {
374         if (!encoder)
375                 return;
376
377         shadow_encoder_uninit(encoder);
378
379         free(encoder);
380 }