4e8e0004cec9eed47e5c562f106f643dde590340
[platform/upstream/freerdp.git] / server / X11 / xf_encode.c
1 /**
2  * FreeRDP: A Remote Desktop Protocol Implementation
3  * X11 RemoteFX Encoder
4  *
5  * Copyright 2011 Marc-Andre Moreau <marcandre.moreau@gmail.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 #ifdef HAVE_CONFIG_H
21 #include "config.h"
22 #endif
23
24 #include <X11/Xlib.h>
25
26 #include <sys/select.h>
27 #include <sys/signal.h>
28
29 #include <freerdp/utils/sleep.h>
30
31 #include "xf_encode.h"
32
33 XImage* xf_snapshot(xfPeerContext* xfp, int x, int y, int width, int height)
34 {
35         XImage* image;
36         xfInfo* xfi = xfp->info;
37
38         if (xfi->use_xshm)
39         {
40                 pthread_mutex_lock(&(xfp->mutex));
41
42                 XCopyArea(xfi->display, xfi->root_window, xfi->fb_pixmap,
43                                 xfi->xdamage_gc, x, y, width, height, x, y);
44
45                 XSync(xfi->display, False);
46
47                 image = xfi->fb_image;
48
49                 pthread_mutex_unlock(&(xfp->mutex));
50         }
51         else
52         {
53                 pthread_mutex_lock(&(xfp->mutex));
54
55                 image = XGetImage(xfi->display, xfi->root_window,
56                                 x, y, width, height, AllPlanes, ZPixmap);
57
58                 pthread_mutex_unlock(&(xfp->mutex));
59         }
60
61         return image;
62 }
63
64 void xf_xdamage_subtract_region(xfPeerContext* xfp, int x, int y, int width, int height)
65 {
66         XRectangle region;
67         xfInfo* xfi = xfp->info;
68
69         region.x = x;
70         region.y = y;
71         region.width = width;
72         region.height = height;
73
74 #ifdef WITH_XFIXES
75         pthread_mutex_lock(&(xfp->mutex));
76         XFixesSetRegion(xfi->display, xfi->xdamage_region, &region, 1);
77         XDamageSubtract(xfi->display, xfi->xdamage, xfi->xdamage_region, None);
78         pthread_mutex_unlock(&(xfp->mutex));
79 #endif
80 }
81
82 void* xf_frame_rate_thread(void* param)
83 {
84         xfInfo* xfi;
85         xfEvent* event;
86         xfPeerContext* xfp;
87         freerdp_peer* client;
88         UINT32 wait_interval;
89
90         client = (freerdp_peer*) param;
91         xfp = (xfPeerContext*) client->context;
92         xfi = xfp->info;
93
94         wait_interval = 1000000 / xfp->fps;
95
96         while (1)
97         {
98                 // check if we should terminate
99                 pthread_testcancel();
100                 
101                 event = xf_event_new(XF_EVENT_TYPE_FRAME_TICK);
102                 xf_event_push(xfp->event_queue, (xfEvent*) event);
103                 freerdp_usleep(wait_interval);
104         }
105 }
106
107 void* xf_monitor_updates(void* param)
108 {
109         int fds;
110         xfInfo* xfi;
111         XEvent xevent;
112         fd_set rfds_set;
113         int select_status;
114         int pending_events;
115         xfPeerContext* xfp;
116         freerdp_peer* client;
117         UINT32 wait_interval;
118         struct timeval timeout;
119         int x, y, width, height;
120         XDamageNotifyEvent* notify;
121         xfEventRegion* event_region;
122
123         client = (freerdp_peer*) param;
124         xfp = (xfPeerContext*) client->context;
125         xfi = xfp->info;
126
127         fds = xfi->xfds;
128         wait_interval = (1000000 / 2500);
129         memset(&timeout, 0, sizeof(struct timeval));
130
131         pthread_create(&(xfp->frame_rate_thread), 0, xf_frame_rate_thread, (void*) client);
132
133         while (1)
134         {
135                 // check if we should terminate
136                 pthread_testcancel();
137
138                 FD_ZERO(&rfds_set);
139                 FD_SET(fds, &rfds_set);
140
141                 timeout.tv_sec = 0;
142                 timeout.tv_usec = wait_interval;
143                 select_status = select(fds + 1, &rfds_set, NULL, NULL, &timeout);
144
145                 if (select_status == -1)
146                 {
147                         printf("select failed\n");
148                 }
149                 else if (select_status == 0)
150                 {
151                         //printf("select timeout\n");
152                 }
153
154                 pthread_mutex_lock(&(xfp->mutex));
155                 pending_events = XPending(xfi->display);
156                 pthread_mutex_unlock(&(xfp->mutex));
157
158                 if (pending_events > 0)
159                 {
160                         pthread_mutex_lock(&(xfp->mutex));
161                         memset(&xevent, 0, sizeof(xevent));
162                         XNextEvent(xfi->display, &xevent);
163                         pthread_mutex_unlock(&(xfp->mutex));
164
165                         if (xevent.type == xfi->xdamage_notify_event)
166                         {
167                                 notify = (XDamageNotifyEvent*) &xevent;
168
169                                 x = notify->area.x;
170                                 y = notify->area.y;
171                                 width = notify->area.width;
172                                 height = notify->area.height;
173
174                                 xf_xdamage_subtract_region(xfp, x, y, width, height);
175
176                                 event_region = xf_event_region_new(x, y, width, height);
177                                 xf_event_push(xfp->event_queue, (xfEvent*) event_region);
178                         }
179                 }
180         }
181
182         return NULL;
183 }